如何使用带有无限列表的filterM

use*_*536 7 monads haskell

我试图通过附加一个数字来找到目录名,直到找到一个尚不存在的名称:

head <$> filterM (fmap not . fexists_) [ getDatedDir t d n | n <- [0..] ]
Run Code Online (Sandbox Code Playgroud)

这个问题是它永远不会回来.我认为问题是尽管IO是一个Functor,但filterM必须在头部效果之前完成所有IO; 也就是说,它必须为每个n评估fexists - 这当然是无限的.

现在,我可以解决这个问题:

go t d 0
where go t d n = do
    let dir = getDatedDir t d n
    fexists_ dir >>= \case
        False -> return dir
        True  -> go t d (n+1)
Run Code Online (Sandbox Code Playgroud)

但我觉得应该有更优雅的方法,使用filterM或类似的东西.

这感觉就像一个普通的模式,在Control.Monad中可能存在一个提升功能,我只是没有看到它.

pat*_*pat 5

firstM来自Control.Monad.Loops:

firstM :: Monad m => (a -> m Bool) -> [a] -> m (Maybe a)
Run Code Online (Sandbox Code Playgroud)

返回满足给定谓词的列表中的第一个值(如果有).