如何編寫一個在列表元素之間進行邏輯和函數操作的函數?Haskell IO布爾摺疊問題
我寫了這個:
iand :: [IO Bool] -> IO Bool
iand [] = return (True)
iand (x:xs) = do
a <- x
b <- iand(xs)
return (a && b)
不過,這似乎是unconscice。
這個函數如何用foldM(liftM)重寫?
謝謝。
如何編寫一個在列表元素之間進行邏輯和函數操作的函數?Haskell IO布爾摺疊問題
我寫了這個:
iand :: [IO Bool] -> IO Bool
iand [] = return (True)
iand (x:xs) = do
a <- x
b <- iand(xs)
return (a && b)
不過,這似乎是unconscice。
這個函數如何用foldM(liftM)重寫?
謝謝。
前奏曲功能and :: [Bool] -> Bool
幾乎你想要做什麼,但它不是一元。一般來說,要將單參數函數提升爲monad,您需要Control.Monad的liftM :: Monad m => (a -> b) -> m a -> b a
;但是,更一般的,你可以使用Prelude的fmap :: Functor f => (a -> b) -> f a -> f b
。所有單子都是仿函子,所以這沒關係。因此,你可以使用
fand' :: Functor f => f [Bool] -> f Bool
fand' = fmap and
然而,至少有90%的時間,我只想寫直列作爲fmap and xs
,更可能是and <$> xs
,使用Control.Applicative的<$>
代名詞fmap
。
當然,正如我相信你注意到的,這不是你想要的。爲此,你需要Prelude的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
我從fmap
切換到liftM
,因爲儘管fmap
的‘更好’,在某種意義上說,它會造成額外Functor m
約束。 不應該是是一個問題,但它可能是由於歷史原因,所以我玩它很安全。
此外,你可能會問:「我怎麼會知道sequence
」?答案是美妙的Hoogle,它允許您按名稱或類型搜索Haskell函數。所以,既然你知道liftM :: Monad m => (a -> b) -> m a -> m b
,你可能已經意識到你需要類似Monad m => [m a] -> m [a]
;爲那does indeed turn up sequence
ogogling。
1:或者,至少,他們應該是,由於歷史的原因,不過,這並非總是如此。
會不會是iand list = foldl (&&) True list
?
不會。這是''[Bool] - > Bool'類型的函數,與普通的'and'類似,但不太懶惰。德米特里想要的是'[IO Bool] - > IO Bool'的函數。 – sepp2k 2010-12-11 23:01:52
對。錯過了。對困惑感到抱歉。 – 2010-12-11 23:03:06
您可以使用liftM
打開and
(其類型爲[Bool] -> Bool
)到IO [Bool] -> IO Bool
類型和sequence
的功能,把你的[IO Bool]
到IO [Bool]
。
所以你的函數變爲:
iand ibs = liftM and (sequence ibs)
謝謝!但是說:「無法匹配預期類型'm'與推斷類型'[]'」到mand函數。那裏有什麼問題? – 4DA 2010-12-12 00:07:38
@Dmitry:糟糕,那是因爲我輸錯了。我主張''mand :: Monad m => m [Bool] - > m Bool',這顯然很愚蠢,因爲這個練習的*點*是爲你創建一個類型爲'Monad m => [m Bool ] - > m Bool'。如果你修復了這個類型的斷言,一切正常。我已經相應地編輯了我的答案。 – 2010-12-12 00:10:08