【问题标题】:Is there a lazy mapM?有懒mapM吗?
【发布时间】:2016-01-22 15:25:28
【问题描述】:

乍一看,我认为这两个函数的工作方式是一样的:

firstM _ []     = return Nothing
firstM p (x:xs) = p x >>= \r -> if r then return (Just x) else firstM p xs

firstM' p xs    = fmap listToMaybe (mapM p xs)

但他们没有。特别是,一旦第一个 p x 为真,firstM 就会停止。但是firstM',因为mapM,需要评估整个列表。

是否存在启用第二个定义的“惰性mapM”,或者至少一个不需要显式递归的定义?

【问题讨论】:

  • 你的意思是fmap listToMaybe (filterM p xs)
  • 你在哪个 monad 中运行你的两个函数? (特别是,我怀疑部分答案是“没有适用于所有moands的'lazy mapM'的定义”,部分答案是“IO的lazy mapM基本上以Haskell的方式混合动作和惰性评估是旨在避免”)。
  • firstMfirstM' 具有不同的类型 语义。第一个是Monad m => (a -> m Bool) -> [a] -> m (Maybe a),而后者是Monad m => (a -> m b) -> [a] -> m (Maybe b)。你确定吗?

标签: haskell monads lazy-evaluation


【解决方案1】:

没有(不可能)安全的Monad-多态懒惰mapM。但the monad-loops package 包含许多惰性单子变体的各种纯函数,包括firstM

【讨论】:

    【解决方案2】:

    一种解决方案是使用ListT,列表单子转换器。这种类型将副作用和结果交错,因此您无需先运行整个计算即可查看初始元素。

    这是一个使用ListT的例子:

    import Control.Monad
    import qualified ListT
    
    firstM :: Monad m => (a -> Bool) -> [a] -> m (Maybe a)
    firstM p = ListT.head . mfilter p . ListT.fromFoldable
    

    (注意transformersmtl中定义的ListTbuggy,不应该使用。不过我上面链接的版本应该没问题。)

    【讨论】:

      【解决方案3】:

      如果有的话,我怀疑它叫mapM

      我记得,mapM 是根据sequence 定义的:

      mapM :: Monad m => (a -> b) -> [a] -> m [b]
      mapM f = sequence . map f
      

      sequence 的全部意义在于保证在给你任何东西之前所有的副作用都已经完成。

      相对于使用一些备用的mapM,您可以只使用mapsequence,因此您可以将容器从[a] 更改为Just a

      firstM p xs = sequence $ listToMaybe (map p xs)
      

      甚至:

      firstM p xs = mapM f $ listToMaybe xs
      

      现在mapMsequence 可以对通用Traversables 进行操作,而不仅仅是列表。

      【讨论】:

      • 问题中的 firstM' 可能具有误导性,因为 firstM 实际上采用了满足单子谓词的第一个元素。
      猜你喜欢
      • 2012-09-18
      • 1970-01-01
      • 1970-01-01
      • 2021-12-18
      • 2018-01-28
      • 1970-01-01
      • 2011-03-09
      相关资源
      最近更新 更多