我基本上在寻找find
的{{1}}类似物:
filterM
但我无法使用findM :: (a -> m Bool) -> [a] -> m (Maybe a)
和某种提升功能自行编写。我目前正在通过find
:
Data.Maybe.listToMaybe
有效,但似乎我应该能够直接使用x <- filterM f list
return $ listToMaybe x
。
编辑:在hackage上找到一些东西:Control.Monad.Loops.firstM和Control.Monad.TM.findM都做我想要的事情
答案 0 :(得分:1)
好吧,你可以像“
”一样从头开始写findM p ls =
case ls of
[] -> return Nothing
x:xs -> do
ok <- p x
if ok
then return (Just x)
else findM p xs
虽然我意识到这比你要求的要优雅得多。我无法弄清楚如何使用某种提升功能来做到这一点。我觉得提升必须在find
的递归步骤中发生,它隐藏在函数内部并且无法被提升。虽然我很乐意看到有人证明我错了。
答案 1 :(得分:1)
这是一个无聊,直接的实施:
findM :: Monad m => (a -> m Bool) -> [a] -> m (Maybe a)
findM _ [] = return Nothing
findM f (x:xs) = do
found <- f x
if found
then return $ Just x
else findM f xs
请注意,此findM
不会将f
应用于找到的项目之后的任何项目。因此,它在语义上与您发布的filterM
实现不同。
您无法在不遗漏的情况下根据find
撰写此内容。您已有纯列表,但谓词(a -> m Bool)
与(a -> Bool)
所需的find
不符。如果您使用mapM
将谓词应用于每个项目,则只需[Bool]
,您需要将其压缩到原始列表中。