题
如何编写列表元素之间逻辑和函数的函数?
我写了这一点:
iand :: [IO Bool] -> IO Bool
iand [] = return (True)
iand (x:xs) = do
a <- x
b <- iand(xs)
return (a && b)
但这似乎是不怀疑的。
如何使用FoldM(LiftM)重写此功能?
谢谢你。
解决方案
前奏功能 and :: [Bool] -> Bool
几乎可以做您想要的,但这不是单一的。一般来说,要将单题功能提升到单片中,您需要控制。 liftM :: Monad m => (a -> b) -> m a -> b a
;但是,更一般地,您可以使用前奏 fmap :: Functor f => (a -> b) -> f a -> f b
. 。所有单子都是函子1, ,所以可以。因此,您可以使用
fand' :: Functor f => f [Bool] -> f Bool
fand' = fmap and
但是,至少有90%的时间,我只是将其写为 fmap and xs
, ,或更可能 and <$> xs
, ,使用Control.Applicative's <$>
同义词 fmap
.
当然,正如我确定您注意到的那样,这不是您想要的。为此,您需要前奏 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
我切换了 liftM
从 fmap
因为,虽然 fmap
从某种意义上说,“更好”的 Functor m
约束。那 不应该 成为一个问题,但可能是出于历史原因,所以我安全地玩了。
另外,您可能会问:“我将如何了解 sequence
“?答案是美妙的 霍格, ,这使您可以按名称搜索Haskell功能 或类型. 。所以,既然你知道 liftM :: Monad m => (a -> b) -> m a -> m b
, ,您可能已经意识到您需要类似的东西 Monad m => [m a] -> m [a]
;为此 确实出现了 sequence
.
1: 或者,至少应该是 - 出于历史原因,并非总是如此。
其他提示
您可以使用 liftM
转 and
(有类型 [Bool] -> Bool
)变成类型的函数 IO [Bool] -> IO Bool
和 sequence
转过你的 [IO Bool]
进入 IO [Bool]
.
因此您的功能变为:
iand ibs = liftM and (sequence ibs)
不会 iand list = foldl (&&) True list
?