Haskell Maybe 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=<<fx,或等效地定义为(f>=>g)x=fx>>=g。有了它,上面的定义就变成了
takeOneEighth :: Int -> Maybe Int takeOneEighth = halve <=< halve <=< halve -- infixr 1 <=< -- or, equivalently, -- halve >=> halve >=> halve -- infixr 1 >=>
每个monad(即作为Monadtypeclass的一个实例的每个类型)都应遵循三个monad法则:
1. return x >>= f = f x 2. m >>= return = m 3. (m >>= g) >>= h = m >>= (\y -> g y >>= h)
mmonad在哪里,f具有typea->mb和gtypeb->mc。
或者等效地,使用>=>上面定义的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 } }
遵守这些定律使对单子的推理变得容易得多,因为它保证了使用单子函数并组成它们的行为与其他单子一样合理。
让我们检查一下Maybemonad是否遵守这三个monad定律。
左身份法-returnx>>=f=fx
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->fx>>=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