【问题标题】:Monadic folding of Data.TextData.Text 的一元折叠
【发布时间】:2018-12-04 13:12:07
【问题描述】:

我想写一个函数

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 都是热切的和非单子的,Data.Text.Lazy 已被警告不要。这是拔出conduitpipes 的地方吗?

【问题讨论】:

  • 您的frequencies 看起来也不正确:它不是总是返回M.empty 吗?我想你想要更像M.insertWith
  • 我不知道Data.Text.Lazy 有什么固有的错误。将其用于惰性 I/O 会导致与其他惰性 I/O 相同的一般问题,但仅将其用作数据结构应该没有问题。

标签: haskell monads lazy-sequences


【解决方案1】:

Text 不能是Traversable,因为它没有使用其元素的类型进行参数化——它总是包含Chars,仅此而已。换句话说,它是一个“单态容器”而不是多态容器。

对于“单态容器”,我们有MonoTraversable,它提供omapM

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

这意味着,对于Text

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

【讨论】:

  • 哇,谢谢。我不知道这存在。因此,对于我的问题,由于我将[Char] 转换为Either String [Int]mapM toDigit,而omapM 产生Applicative m =&gt; m Text,您是否建议使用otoList 来实现中间列表或流在我正在生成的Data.Map 中增加适当的键值对之前的整数?
  • 没关系!我也看到了ofoldM
  • @SimonShine 是的,折叠可能是您需要的。我认为所有标准仿函数/可折叠/可遍历函数也可以在它们的“单”变体中使用。
  • @SimonShine,当您可以侥幸逃脱时,您绝对应该更喜欢折叠(来自MonoFoldable 或只是(懒惰的)Data.Text.Strict.foldr)而不是遍历。 otraverse for Text 通过简单的拆包和打包转换为字符串并返回;这真的很低效。在Maybe 中遍历(如果那是你真正想要的)几乎可以肯定使用低级自定义函数(粗略地说,在MaybeT (ST s) 中遍历)做得更好。但在这种情况下,最好完全避开并发症。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-10-13
  • 1970-01-01
  • 2020-09-15
  • 2016-03-14
  • 2015-02-09
  • 2013-05-31
  • 1970-01-01
相关资源
最近更新 更多