5. 변종1: 예외 처리
data M a = Raise Exception | Return a
type Exception = String
6. 변종1: 예외 처리
eval :: Term -> M Int
eval (Con a) = Return a
eval (Div t u) = case eval t of
Raise e -> Raise e
Return a ->
case eval u of
Raise e -> Raise e
Return b ->
if b == 0
then Raise “divide by zero”
else Return (a `div` b)
8. 변종2: division 카운터
eval :: Term -> M Int
eval (Con a) x = (a, x)
eval (Div t u) x = let (a, y) = eval t x in
let (b, z) = eval u y in
(a `div` b, z + 1)
9. 변종3: 실행 과정 출력
type M a = (Output, a)
type Output = String
10. 변종3: 실행 과정 출력
eval :: Term -> M Int
eval @term(Con a) = (line term a, a)
eval @term(Div t u) = let (x, a) = eval t in
let (y, b) = eval u in
(x ++ y ++ line term (a `div` b), a `div` b)
line :: Term -> Int -> Output
line t a = “eval (“ ++ show t ++ “) <-” ++ show a ++ “n”
11. Monadic Evaluator
eval :: (Moand m) => Term -> m Int
eval (Con a) = return a
eval (Div t u) = do a <- eval t
b <- eval u
return (a `div` b)
12. Monadic Evaluator
eval :: (Moand m) => Term -> m Int
eval (Con a) = return a
eval (Div t u) = do a <- eval t
b <- eval u
return (a `div` b)
14. 변종1: 예외 처리
data M a = Raise Exception | Return a
type Exception = String
instance Monad M where
return a = Return a
m >>= k = case m of
Raise e -> Raise e
Return a -> k a
raise :: Exception -> M a
raise e = Raise e
15. 변종1: 예외 처리
eval :: Term -> M Int
eval (Con a) = return a
eval (Div t u) = do a <- eval t
b <- eval u
if b == 0
then raise “divide by zero”
else return (a `div` b)
16. 변종2: division 카운터
type M a = State -> (a, State)
type State = Int
instance Monad M where
return a = x -> (a, x)
m >>= k = x -> let (a, y) = m x in
let (b, z) = k a y in
(b, z)
tick :: M ()
tick = x -> ((), x + 1)
17. 변종2: division 카운터
eval :: Term -> M Int
eval (Con a) = return a
eval (Div t u) = do a <- eval t
b <- eval u
tick
return (a `div` b)
18. 변종3: 실행 과정 출력
type M a = (Output, a)
type Output = String
instance Monad m where
return a = (“”, a)
m >>= k = let (x, a) = m in
let (y, b) = k a in
(x ++ y, b)
out :: Output -> M ()
out x = (x, ())
19. 변종3: 실행 과정 출력
eval :: Term -> M Int
eval term@(Con a) = do out (line term a)
return a
eval term@(Div t u) = do a <- eval t
b <- eval u
out (line term (a `div` b))
return (a `div` b)
20. Control.Monad
• mapM :: Monad m => (a -> m b) -> [a] -> m [b]
• forM :: Monad m => [a] -> (a -> m b) -> m [b]
• sequence :: Monad m => [m a] -> m [a]
Note: [t] generalizes to Traversable t
23. Parser
newtype Parser a = Parser (String -> [a, String])
• empty 리스트는 실패, 아니면 성공
• (a, s)에서 a는 파싱한 결과 s는 파싱하고 남은 문자
열
• 리스트를 리턴하여 ambiguous grammar 처리
24. item
• 문자열이 empty가 아니면 첫 번째 문자를 리턴
• empty이면 에러
item :: Parser Char
item = Parser (cs -> case cs of
"" -> []
(c:cs) -> [(c, cs)])
25. 모나드 정의
class Monad m where
return :: a -> m a
(>>=) :: m a -> (a -> m b) -> m b
instance Monad Parser where
return a = (Parser (cs -> [(a, cs)])
p >>= f = (Parser (cs -> concat [parse (f a) cs’ |
(a, cs’) <- parse p cs])
parse (Parser p) = p
26. 모나드 법칙
1. return a >> f = f a
2. p >>= return = p
3. p >>= (a -> (f a) >>= g)) = (p >>= (a -> f a)) >>= g
27. Do 표기법
p1 >>= a1 ->
p2 >>= a2 ->
…
pn >>= an ->
f a1 a2 … an
do a1 <- p1
a2 <- p2
…
an <- pn
f a1 a2 … an
28. Do 표기법 사용 예제
p :: Parser (Char, Char)
p = do c <- item
item
d <- item
return (c, d)
29. MonadZero, MonadPlus
class Monad m => MonadZero m where
zero :: m a
class MonadZero m => MonadPlus m where
(++) :: m a -> m a -> m a
30. Choice Operator
instance MonadZero Parser where
zero = Parser (cs -> [])
instance MonadPlus Parser where
p ++ q = (Parser (cs ->
parse p cs ++ parse q cs))
31. 법칙
• zero ++ p = p
• p ++ zero = p
• p ++ (q ++ r) = (p ++ q) ++ r
• zero >>= f = zero
• p >>= const zero = zero
• (p ++ q) >>= f = (p >>= f) ++ (q >>= f)
• p >>= (a -> f a ++ g a) = (p >>= f) ++ (q >>= g)
33. Conditional Parsing
sat :: (Char -> Bool) -> Parser Char
sat p = do c <- item
if p c then return c
else zero
char :: Char -> Parser Char
char c = sat (c ==)
35. 재귀 Combinator
many :: Parser a -> Parser [a]
many p = many1 p +++ return []
many1 :: Parser a -> Parser [a]
many1 p = do a <- p
as <- many p
return (a:as)
36. 재귀 Combinator
sepby :: Parser a -> Parser b -> Parser [a]
p `sepby` q = (p `sepby1` q) +++ return []
sepby1 :: Parser a -> Parser b -> Parser [a]
p `sepby1` q = do a <- p
as <- many (do {sep; p})
return (a:as)
37. 재귀 Combinator
chainl :: Parser a -> Parser (a -> a -> a) -> a -> Parser a
chainl p op a = (p `chainl1` op) +++ return a
chainl1 :: Parser a -> (Parser a -> a -> a) -> Parser a
p `chainl1` op = do { a <- p; rest a }
where rest a = (do f <- op
b <- p
return f a b)
+++ return a
38. Lexical Combinators
space :: Parser String
space = many (sat isSpace)
token :: Parser a -> Parser a
token p = do a <- p
space
return a
47. Tree 업데이트
changeToP :: Tree Char -> Tree Char
changeToP (Node x l (Node y (Node _ m n) r)) =
Node x l (Node y (Node 'P' m n) r)
48. Tree 업데이트
data Direction = L | R deriving (Show)
type Directions = [Direction]
changeToP :: Directions -> Tree Char -> Tree Char
changeToP (L:ds) (Node x l r) = Node x (changeToP ds l) r
changeToP (R:ds) (Node x l r) = Node x l (changeToP ds r)
changeToP [] (Node _ l r) = Node 'P' l r
49. element
elemAt :: Directions -> Tree a -> a
elemAt (L:ds) (Node _ l _) = elemAt ds l
elemAt (R:ds) (Node _ _ r) = elemAt ds r
elemAt [] (Node x _ _) = x
53. Zipper 정의
data Crumb a =
LeftCrumb a (Tree a)
| RightCrumb a (Tree a)
deriving (Show)
type Breadcrumbs a = [Crumb a]
54. Zipper 함수
goLeft :: (Tree a, Breadcrumbs a)
-> (Tree a, Breadcrumbs a)
goLeft (Node x l r, bs) = (l, LeftCrumb x r:bs)
goRight :: (Tree a, Breadcrumbs a)
-> (Tree a, Breadcrumbs a)
goRight (Node x l r, bs) = (r, RightCrumb x l:bs)
55. Zipper 함수
goUp :: (Tree a, Breadcrumbs a)
-> (Tree a, Breadcrumbs a)
goUp (t, LeftCrumb x r:bs) =
(Node x t r, bs)
goUp (t, RightCrumb x l:bs) =
(Node x l t, bs)
64. 참고 자료
1. Monads for functional programming
• http://homepages.inf.ed.ac.uk/wadler/papers/markto
berdorf/baastad.pdf
2. Monadic Parsing in Haskell
• http://www.cs.nott.ac.uk/~pszgmh/pearl.pdf
3. Learn You a Haskell for Great Good!
• http://learnyouahaskell.com/zippers