如何编写一个在列表元素之间具有逻辑和功能的函数?
我写了这个:
iand :: [IO Bool] -> IO Bool
iand [] = return (True)
iand (x:xs) = do
a <- x
b <- iand(xs)
return (a && b)
Run Code Online (Sandbox Code Playgroud)
但这似乎是不切实际的.
如何用foldM(liftM)重写这个功能?
谢谢.
Ant*_*sky 10
Prelude功能and :: [Bool] -> Bool几乎可以达到你想要的效果,但它并不是monadic.一般来说,要将单参数函数提升为monad,你需要Control.Monad的liftM :: Monad m => (a -> b) -> m a -> b a; 但是,更一般地说,你可以使用Prelude's fmap :: Functor f => (a -> b) -> f a -> f b.所有monad都是仿函数1,所以这没关系.因此,你可以使用
fand' :: Functor f => f [Bool] -> f Bool
fand' = fmap and
Run Code Online (Sandbox Code Playgroud)
但是,至少有90%的时间,我只是使用Control.Applicative的同义词来内联fmap and xs,或者更可能是.and <$> xs<$>fmap
当然,正如我相信你注意到的,这不是你想要的.为此,你需要Prelude's sequence :: Monad m => [m a] -> m [a].你现在有一个函数[m a] -> m [a]和一个函数f [Bool] -> f Bool,所以我们可以结合这些:
mand :: Monad m => [m Bool] -> m Bool
mand = liftM and . sequence
Run Code Online (Sandbox Code Playgroud)
我切换到liftM从fmap,因为尽管fmap的'更好’,在某种意义上说,它会施加额外的Functor m限制.这应该不是问题,但可能是出于历史原因,所以我玩得很安全.
另外,你可能会问"我怎么会知道sequence"?答案就是精彩的Hoogle,它允许您按名称或类型搜索Haskell函数.所以,既然你知道liftM :: Monad m => (a -> b) -> m a -> m b,你可能已经意识到你需要的东西Monad m => [m a] -> m [a]; Hoogling对于确实打开了sequence.
1:或者,至少,它们应该是 - 出于历史原因,但情况并非总是如此.