乍一看,我认为这两个功能的作用相同:
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)
但他们不是。特别是,只要第一个firstM
为真,p x
就会停止。但由于firstM'
,mapM
需要对整个列表进行评估。
是否存在"懒惰mapM
"启用第二个定义,或者至少一个不需要显式递归的定义?
答案 0 :(得分:2)
一种解决方案是使用列表monad转换器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
(请注意,ListT
和transformers
中定义的mtl
为buggy,不应使用。我上面链接的版本应该没问题。)< / p>
答案 1 :(得分:1)
如果有,我怀疑它被称为mapM
。
我记得,mapM
是根据sequence
:
mapM :: Monad m => (a -> b) -> [a] -> m [b]
mapM f = sequence . map f
并且sequence
的重点是保证在给你任何东西之前完成所有的副作用。
与使用某些替代mapM
相反,您只需使用map
和sequence
就可以逃脱,因此您可以将容器从[a]
更改为{{1 }}:
Just a
甚至:
firstM p xs = sequence $ listToMaybe (map p xs)
现在firstM p xs = mapM f $ listToMaybe xs
和mapM
可以对通用sequence
进行操作,而不仅仅是列表。
答案 2 :(得分:1)
没有(不可能)安全,Monad
- 多态懒惰mapM
。但是the monad-loops
package包含许多各种纯函数的惰性monadic变体,包括firstM
。