Data.Text 的单次折叠

Monadic folding of Data.Text

我想写一个函数

countDigits :: Text -> Either Text (Map Int Int)

构建数字字符的直方图,如果存在非数字字符并带有指示第一个或所有非数字字符的消息,则会失败。如果这是 String 我可以写类似

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)

但由于 Data.Text 不是 Foldable,我无法使用 mapM

事实上,将Data.Text值转换为任何惰性流值似乎有点困难。 (folds of Data.Text.Strict 都是 eager 和 non-monadic,并且 Data.Text.Lazy 已被警告。这是拉出 conduitpipes 的地方吗?

Text 不能是 Traversable 因为它没有用它的元素类型参数化——它总是包含 Char,没有别的。换句话说,它是一个"monomorphic container"而不是一个多态的。

对于 "monomorphic containers" 我们有 MonoTraversable 提供 omapM:

omapM :: Applicative m => (Element mono -> m (Element mono)) -> mono -> m mono 

这意味着,在 Text 的情况下,

omapM :: Applicative m => (Char -> m Char) -> Text -> m Text