2013-11-24 6 views
6

我可以看到你如何使用Monad是用於IO的Haskell - 圍繞此操作的計算創建一個容器。您可以使用Monads來「一起插入計算」 - 這與您爲數據流操作編寫函數相同。Monads控制流 - 序列,選擇和迭代

什麼我只是grokking是你可以使用Monads控制流。現在我明白控制流程是關於序列,選擇和迭代。現在我對諸如map,foldl,filter和zipwith/mapcat等高階函數感到滿意,可以對列表執行操作。

我的問題是 - 我可以做序列,選擇和monads迭代,以實現控制流? (快樂在Haskell中,斯卡拉或Clojure的答案)

回答

5

對於Haskell的排序,你具備的功能>>=sequence

(>>=) :: Monad m => m a -> (a -> m b) -> m b 
sequence :: Monad m => [m a] -> m [a] 

>>=或綁定功能需要一個單子行動,提取值從它並將它提供給一個函數,返回一個新的monadic動作。 sequence函數獲取相同類型的monadic動作列表,並執行所有這些動作,彙總其結果並將其作爲單個動作進行封裝。

對於迭代你有mapMforMforM = flip mapM

mapM :: Monad m => (a -> m b) -> [a] -> m [b] 

mapMforM功能是用於將返回到各元件的動作列表中的一個功能,綜合這些結果作爲一個單一的動作。

對於選擇,我假設你的意思是條件,這些條件在Haskell中就像if-the-else表達式一樣實現。它們可以在monadic表達式中直接使用,它們可以在純表達式中使用。但是,您也可以使用某些monads來執行選擇或至少處理錯誤。最容易的是Maybe monad:

data Maybe a = Nothing | Just a 

instance Monad Maybe where 
    return a = Just a 
    (Just a) >>= f = f a 
    Nothing >>= f = Nothing 

它有一個非常簡單的實現。實質上,如果您嘗試將Nothing排序爲其他任何內容,則每次都會返回Nothing。這給你短路故障的概念:

lookup :: Eq a => a -> [(a, b)] -> Maybe b 
-- Looks up a value in a key-value association list 

myFunc :: Int -> [(String, Int)] -> Maybe Int 
myFunc mult assocList = do 
    i <- lookup "foo" assocList 
    j <- lookup "bar" assocList 
    return $ i * mult + j 

這裏,如果"foo"查找失敗,則myFunc立即返回Nothing。同樣,如果"bar"的查找失敗,則myFunc立即返回Nothing。只有當兩個查找都成功時,myFunc纔會進行任何計算。這提供了一種「錯誤處理」。還有一個類似的單子Either a

data Either a b = Left a | Right b 

instance Monad (Either a) where 
    return a = Right a 
    (Right a) >>= f = f a 
    (Left a) >>= f = Left a 

的作品大同小異,不同的是「失敗」的值可以隨身攜帶一些方面,如字符串錯誤消息或計算在故障點的狀態。

+1

「>> =」是否真的能夠保證排序或僅僅是最常見單子的行爲? – kqr

+1

@kqr它不保證評估的順序,如果這是你問的問題。原因是評估的順序取決於'(>> =)'的定義,而不是所有的實現都是在第二個參數之前評估第一個參數。 –

+0

@kqr它不能保證排序,但它是允許我們使用'do'符號的函數,這就是我將問題解釋爲問的問題。由於bind基本上爲do語句中的每個動作定義了(隱含的)分號,因此它給了我們一種爲特定代碼塊定義控制流方面的方法。 – bheklilr