可能的 monad
Maybe
用於表示可能為空的值 - 類似於其他語言中的 null
。通常它被用作可能以某種方式失敗的函式的輸出型別。
考慮以下功能:
halve::Int -> Maybe Int
halve x
| even x = Just (x `div` 2)
| odd x = Nothing
將 halve
視為一個動作,取決於 Int
,它試圖將整數減半,如果它是奇數則失敗。
我們怎樣 halve
整數三次?
takeOneEighth::Int -> Maybe Int -- (after you read the 'do' sub-section:)
takeOneEighth x =
case halve x of -- do {
Nothing -> Nothing
Just oneHalf -> -- oneHalf <- halve x
case halve oneHalf of
Nothing -> Nothing
Just oneQuarter -> -- oneQuarter <- halve oneHalf
case halve oneQuarter of
Nothing -> Nothing -- oneEighth <- halve oneQuarter
Just oneEighth ->
Just oneEighth -- return oneEighth }
takeOneEighth
是連結在一起的三個halve
步驟的序列。- 如果一個
halve
步驟失敗,我們希望整個組合takeOneEighth
失敗。 - 如果
halve
步驟成功,我們希望將結果向前推進。
instance Monad Maybe where
-- (>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b
Nothing >>= f = Nothing -- infixl 1 >>=
Just x >>= f = Just (f x) -- also, f =<< m = m >>= f
-- return::a -> Maybe a
return x = Just x
現在我們可以寫:
takeOneEighth::Int -> Maybe Int
takeOneEighth x = halve x >>= halve >>= halve -- or,
-- return x >>= halve >>= halve >>= halve -- which is parsed as
-- (((return x) >>= halve) >>= halve) >>= halve -- which can also be written as
-- (halve =<<) . (halve =<<) . (halve =<<) $ return x -- or, equivalently, as
-- halve <=< halve <=< halve $ x
Kleisli 組成 <=<
定義為 (g <=< f) x = g =<< f x
,或等同於 (f >=> g) x = f x >>= g
。有了它,上面的定義變得公正
takeOneEighth::Int -> Maybe Int
takeOneEighth = halve <=< halve <=< halve -- infixr 1 <=<
-- or, equivalently,
-- halve >=> halve >=> halve -- infixr 1 >=>
每個 monad 都應該遵守三個 monad 法則,即每個型別都是 Monad
型別類的一個例項:
1. return x >>= f = f x
2. m >>= return = m
3. (m >>= g) >>= h = m >>= (\y -> g y >>= h)
其中 m
是 monad,f
的型別為 a -> m b
,g
的型別為 b -> m c
。
或者等效地,使用上面定義的 >=>
Kleisli 合成運算子:
1. return >=> g = g -- do { y <- return x ; g y } == g x
2. f >=> return = f -- do { y <- f x ; return y } == f x
3. (f >=> g) >=> h = f >=> (g >=> h) -- do { z <- do { y <- f x; g y } ; h z }
-- == do { y <- f x ; do { z <- g y; h z } }
遵守這些定律使得更容易推理 monad,因為它保證使用 monadic 函式並組合它們的行為方式與其他 monad 相似。
讓我們來看看 Maybe
monad 是否遵守三個 monad 法則。
- 左身份法 -
return x >>= f = f x
return z >>= f
= (Just z) >>= f
= f z
- 正確的身份法 -
m >>= return = m
Just
資料建構函式
Just z >>= return
= return z
= Just z
Nothing
資料建構函式
Nothing >>= return
= Nothing
- 結社法 -
(m >>= f) >>= g = m >>= (\x -> f x >>= g)
Just
資料建構函式
-- Left-hand side
((Just z) >>= f) >>= g
= f z >>= g
-- Right-hand side
(Just z) >>= (\x -> f x >>= g)
(\x -> f x >>= g) z
= f z >>= g
Nothing
資料建構函式
-- Left-hand side
(Nothing >>= f) >>= g
= Nothing >>= g
= Nothing
-- Right-hand side
Nothing >>= (\x -> f x >>= g)
= Nothing