Thực Hành Monad trong Haskell

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]

Thẻ: Haskell Monad State Monad Reader Monad Writer Monad

Đăng vào ngày 23 tháng 6 lúc 13:15