findM :: Monad m => (a -> m Bool) -> m [a] -> Maybe (m a)
我不能自己实现它。我可以使用一些指针
看起来像:
find f as = listToMaybe $ filter f as
所以我试过了:
findM f as = filterM f as >>= listToMaybe
但它不起作用。
答案 0 :(得分:10)
没有。这不可能。但是,您可以使用签名编写一个函数:
findM :: Monad m => (a -> m Bool) -> m [a] -> m (Maybe a)
不可能的原因是,为了确定Maybe
是否具有构造函数Just x
或Nothing
,您必须从monad中获取值。这意味着Maybe
必须在最后的monad中,因为通常不可能从monad中提取值。 (毕竟,这是monad的重点。)
例如,鉴于您对findM
的签名,您可能会写一些明显不正确的函数:
findM :: Monad m => (a -> m Bool) -> m [a] -> Maybe (m a)
findM = magic
anyM :: Monad m => (a -> m Bool) -> m [a] -> Bool
anyM f = isJust . findM f
extractBool :: Monad m => m Bool -> Bool
extractBool = anyM id . liftM (:[])
函数extractBool
显然是不可能的,因此findM
无法签名。
以下是findM
的实现:
findM :: Monad m => (a -> m Bool) -> [a] -> m (Maybe a)
findM _ [] = return Nothing
findM f (x:xs) = do y <- f x
if y then return (Just x) else findM f xs
我不确定一种更简单的方法来实现它 - 这看起来相当干净,并且可以在无限列表上运行。
将签名从使用m [a]
更改为使用[a]
会使其更有用,更易于使用。如果你实现这两个接口,你会很快找出原因。
答案 1 :(得分:7)
尝试
findM :: Monad m => (a -> m Bool) -> [a] -> m (Maybe a)
findM p = foldr step (return Nothing)
where
step x r = do
b <- p x
if b then return (Just x) else r
此版本仅使用谓词,而filterM
版本在每个元素上使用谓词。例如:
ghci> let findM' p xs = filterM p xs >>= return . listToMaybe
ghci> let check x = putStrLn ("checking " ++ show x) >> doesDirectoryExist x
ghci> findM check ["test1", ".", "test2"]
checking "test1"
checking "."
Just "."
ghci> findM' check ["test1", ".", "test2"]
checking "test1"
checking "."
checking "test2"
Just "."
答案 2 :(得分:1)
其他人已经证明这是不可能的,但是如果进一步限制你可以得到一个非常相似的功能。
findM :: (Traversable m, Monad m) => (a -> m Bool) -> m [a] -> Maybe (m a)
findM p xs = Data.Traverse.sequence $ dietrichsFindM p xs
并非每个Monad都有一个Traversable实例,但如果它有,这将有效。
答案 3 :(得分:0)
签名
findM :: Monad m => (a -> m Bool) -> m [a] -> m (Maybe a)
我建议:
import Control.Monad
import Data.Maybe
findM :: Monad m => (a -> m Bool) -> m [a] -> m (Maybe a)
findM f m = m >>= filterM f >>= return . listToMaybe
或
findM :: Monad m => (a -> m Bool) -> m [a] -> m (Maybe a)
findM = ((return . listToMaybe =<<) .) . (=<<) . filterM
获得无点风格。