2010-12-11 73 views
1

如何編寫一個在列表元素之間進行邏輯和函數操作的函數?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)重寫?

謝謝。

回答

10

前奏曲功能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:或者,至少,他們應該是,由於歷史的原因,不過,這並非總是如此。

+0

謝謝!但是說:「無法匹配預期類型'm'與推斷類型'[]'」到mand函數。那裏有什麼問題? – 4DA 2010-12-12 00:07:38

+0

@Dmitry:糟糕,那是因爲我輸錯了。我主張''mand :: Monad m => m [Bool] - > m Bool',這顯然很愚蠢,因爲這個練習的*點*是爲你創建一個類型爲'Monad m => [m Bool ] - > m Bool'。如果你修復了這個類型的斷言,一切正常。我已經相應地編輯了我的答案。 – 2010-12-12 00:10:08

1

會不會是iand list = foldl (&&) True list

+0

不會。這是''[Bool] - > Bool'類型的函數,與普通的'and'類似,但不太懶惰。德米特里想要的是'[IO Bool] - > IO Bool'的函數。 – sepp2k 2010-12-11 23:01:52

+0

對。錯過了。對困惑感到抱歉。 – 2010-12-11 23:03:06

2

您可以使用liftM打開and(其類型爲[Bool] -> Bool)到IO [Bool] -> IO Bool類型和sequence的功能,把你的[IO Bool]IO [Bool]

所以你的函數變爲:

iand ibs = liftM and (sequence ibs)