跳轉到內容

Haskell/理解單子/解決方案/IO

來自華夏公益教科書
[編輯 | 編輯原始碼]

map 函式將打印出列表中的每個值,但會生成 [IO ()]。因此我們需要鏈式 sequence $ map,這正是 mapM 函式的定義方式。因為我們不是收集 print 的結果,而是隻關注它的操作,所以我們可以用 mapM_ 來丟棄它們。

printList :: Show a => [a] -> IO ()
printList = mapM_ print

概括兔子入侵示例

[編輯 | 編輯原始碼]

如果我們沒有使用單子,則將函式 f :: a -> a 應用三次將透過 f(f(f(x))) 實現,這可以改寫為 (f . f . f) x。這表明,如果我們想將其推廣到將函式應用 n 次,我們可以使用 (.) 作為累積函式來摺疊 f 列表

composeTimes :: Int -> (a -> a) -> (a -> a)
composeTimes n f = foldr (.) id $ replicate n f

foldr 的初始值為 id,因為 .

現在我們要做的就是將它翻譯成單子,即用單子組合運算子 (>=>) 替換 (.),用 return 替換 id,用 generation 替換任意 f,得到

generations :: Int -> a -> [a]
generations n = foldr (>=>) return $ replicate n generation

我們可以驗證它是否按預期工作

Prelude> ["bunny"] >>= generations 0
["bunny"]
Prelude> ["bunny"] >>= generations 1
["bunny","bunny","bunny"]
Prelude> ["bunny"] >>= generations 2
["bunny","bunny","bunny","bunny","bunny","bunny","bunny","bunny","bunny"]

sequenceMaybe 單子中的預期行為是什麼?

[編輯 | 編輯原始碼]

Maybe 單子表示可能的失敗。如果在計算列表中的任何時候發生錯誤,則整個列表將無法計算,因此我們預期列表的 sequence 將在列表中存在 Nothing 時生成 Nothing,否則生成 Just 列表。這實際上就是發生的情況

Prelude> sequence [Just 1, Just 2, Just 3]
Just [1,2,3]
Prelude> sequence [Just 1, Nothing, Just 3]
Nothing
華夏公益教科書