I would like to write a function
countDigits :: Text -> Either Text (Map Int Int)
that builds a histogram of digit characters and fails if there are non-digit characters with a message that indicates the first or all non-digit characters. If this were with String
I could write something like
countDigits = fmap frequencies . mapM toDigit
where
frequencies :: Ord a => [a] -> Map a Int
frequencies = M.fromListWith (+) . (`zip` [0..9])
toDigit :: Char -> Either String Int
toDigit c = readEither [c] <> Left ("Invalid digit " ++ show c)
but since Data.Text
is not Foldable
, I cannot use mapM
.
In fact, it seems a little difficult to convert a Data.Text
value into any lazy stream value. (The folds of Data.Text.Strict
are all eager and non-monadic, and Data.Text.Lazy
has been warned against. Is this where one pulls out conduit
or pipes
?
Text
can not be a Traversable
since it is not parametrized with the type of its elements -- it always contains Char
s, and nothing else. In other words, it is a "monomorphic container" instead of a polymorphic one.
For "monomorphic containers" we have MonoTraversable
which provides omapM
:
omapM :: Applicative m => (Element mono -> m (Element mono)) -> mono -> m mono
which means, in the case of Text
,
omapM :: Applicative m => (Char -> m Char) -> Text -> m Text