Monad
increase n = Just (n + 1)
addOne n = [n + 1]
main = do
print $ Nothing >> (Just 0) -- Nothing
print $ (Just 0) >> (Nothing :: Maybe Int) -- Nothing
print $ (Just 0) >> Nothing >> (Just 1) -- Nothing
print $ (Just 0) >> (Just 1) >> (Just 2) -- Just 2
print $ Nothing >>= increase >>= increase >>= increase -- Nothing
print $ (Just 0) >>= increase >>= increase >>= increase -- Just 3
print $ [] >> [1, 2] -- []
print $ [1, 2] >> ([] :: [Int]) -- []
print $ [1] >> [3, 4, 5] -- [3,4,5]
print $ [1, 2] >> [3, 4, 5] -- [3,4,5,3,4,5]
print $ [1, 2, 3] >> [3, 4, 5] -- [3,4,5,3,4,5,3,4,5]
print $ [] >>= addOne >>= addOne >>= addOne -- []
print $ [1, 2, 3] >>= addOne -- [2,3,4]
print $ [1, 2, 3] >>= addOne >>= addOne -- [3,4,5]
print $ [1, 2, 3] >>= addOne >>= addOne >>= addOne -- [4,5,6]
Dựa trên định nghĩa Monad Maybe:
instance Monad Maybe where
(Just x) >>= k = k x
Nothing >>= _ = Nothing
Just _m1 >> m2 = m2
Nothing >> _m2 = Nothing
Chúng ta có:
Nothing >>= increase = Nothing
(Just 0) >>= increase
= (Just 0) >>= (\n -> Just (n + 1))
= (\n -> Just (n + 1)) 0
= Just (0 + 1) = Just 1
Nothing >> (Just 0) = Nothing
(Just 0) >> (Nothing :: Maybe Int) = Nothing
(Just 1) >> (Just 2) = Just 2
Dựa trên định nghĩa Monad []:
instance Monad [] where
xs >>= f = [y | x <- xs, y <- f x]
xs >> ys = [y | _ <- xs, y <- ys]
Chúng ta có:
[1, 2, 3] >>= addOne
= [1, 2, 3] >>= (\n -> [n + 1])
= [y | x <- [1, 2, 3], y <- [x + 1]]
= [2,3,4]
[1, 2, 3] >> [3, 4, 5]
= [y | _ <- [1, 2, 3], y <- [3, 4, 5]]
= [3,4,5,3,4,5,3,4,5]
State Monad
import Control.Monad.State
increment :: State Int Int
increment = do
n <- get
put (n + 1)
return n
incrementBy :: Int -> State Int Int
incrementBy x = do
n <- get
modify (+x)
return n
main = do
print $ evalState increment 1 -- 1
print $ execState increment 1 -- 2
print $ runState increment 1 -- (1,2)
print $ runState (withState (+3) increment) 1 -- (4,5)
print $ runState (mapState (\(a, s) -> (a + 3, s + 4)) increment) 1 -- (4,6)
print $ runState (incrementBy 5) 10 -- (10,15)
Về State Monad get đặt giá trị kết quả bằng giá trị trạng thái s, giá trị trạng thái s giữ nguyên. put s đặt giá trị kết quả là rỗng, đặt giá trị trạng thái là s. return a đặt giá trị kết quả là a, giá trị trạng thái s giữ nguyên. modify f đặt giá trị kết quả là rỗng, đặt giá trị trạng thái là f s. gets f đặt giá trị kết quả là f s, giá trị trạng thái s giữ nguyên. Từ đó chúng ta có:
-- Giả sử giá trị trạng thái ban đầu là s
increment = do
n <- get -- (s,s)
put (n + 1) -- ((),s + 1)
return n -- (s,s + 1)
-- Giả sử giá trị trạng thái ban đầu là s
incrementBy x = do
n <- get -- (s,s)
modify (+x) -- ((),s + x)
return n -- (s,s + x)
Về State Monad evalState s thực hiện tính toán trạng thái cho Monad sử dụng giá trị trạng thái ban đầu s, sau đó trả về giá trị kết quả cuối cùng a'. execState s thực hiện tính toán trạng thái cho Monad sử dụng giá trị trạng thái ban đầu s, sau đó trả về giá trị trạng thái cuối cùng s'. runState s thực hiện tính toán trạng thái cho Monad sử dụng giá trị trạng thái ban đầu s, sau đó trả về cặp giá trị (a', s') gồm giá trị kết quả và giá trị trạng thái cuối cùng. mapState f thực hiện tính toán trạng thái cho Monad, sau đó áp dụng hàm f cho giá trị kết quả và giá trị trạng thái. withState f thực hiện tính toán trạng thái cho Monad, trước khi tính toán, áp dụng hàm f cho giá trị trạng thái ban đầu. Từ đó chúng ta có:
runState increment 1 = (1,1 + 1) = (1,2)
evalState increment 1 = 1
execState increment 1 = 2
runState (incrementBy 5) 10 = (10,10 + 5) = (10,15)
runState (withState (+3) increment) 1
= runState increment ((+3) 1)
= runState increment 4
= (4,5)
runState (mapState (\(a, s) -> (a + 3, s + 4)) increment) 1
= (\(a, s) -> (a + 3, s + 4)) (runState increment 1)
= (\(a, s) -> (a + 3, s + 4)) (1,2)
= (4,6)
Reader Monad
import Control.Monad.Reader
data Config = Config { setting1 :: String, setting2 :: String }
getConfig :: Reader Config String
getConfig = do
s1 <- asks setting1 -- Hello
s2 <- asks setting2 -- world!
s3 <- withReader setting1 ask -- Hello
s4 <- mapReader setting2 ask -- world!
return $ s1 ++ ", " ++ s2 ++ ", " ++ s3 ++ ", " ++ s4
main = print $ runReader getConfig $ Config "Hello" "world!"
Writer Monad
import Control.Monad.Writer
logMessage :: Int -> Writer [Int] String
logMessage n = do
tell [1..n]
return "Completed"
main = do
print $ runWriter $ logMessage 10 -- ("Completed",[1,2,3,4,5,6,7,8,9,10])
print $ execWriter $ logMessage 10 -- [1,2,3,4,5,6,7,8,9,10]