하스켈 프로그래밍 입문 3

64
하하하 하하하하하 하하 3 하하하 하하 2016 하 5 하 28 하 하하하

Upload: kwang-yul-seo

Post on 17-Jan-2017

542 views

Category:

Engineering


0 download

TRANSCRIPT

Page 1: 하스켈 프로그래밍 입문 3

하스켈 프로그래밍입문 3하스켈 학교 2016 년 5 월 28 일서광열

Page 2: 하스켈 프로그래밍 입문 3

Identity, State, Writer Monad

Page 3: 하스켈 프로그래밍 입문 3

Term

data Term = Con Int | Div Term Term

Page 4: 하스켈 프로그래밍 입문 3

변종 0: Basic Evaluator

eval :: Term -> Int

eval (Con a) = a

eval (Div t u) = eval t `div` eval u

Page 5: 하스켈 프로그래밍 입문 3

변종 1: 예외 처리data M a = Raise Exception | Return a

type Exception = String

Page 6: 하스켈 프로그래밍 입문 3

변종 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)

Page 7: 하스켈 프로그래밍 입문 3

변종 2: division 카운터type M a = State -> (a, State)

type State = Int

Page 8: 하스켈 프로그래밍 입문 3

변종 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)

Page 9: 하스켈 프로그래밍 입문 3

변종 3: 실행 과정 출력type M a = (Output, a)

type Output = String

Page 10: 하스켈 프로그래밍 입문 3

변종 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”

Page 11: 하스켈 프로그래밍 입문 3

Monadic Evaluatoreval :: (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)

Page 12: 하스켈 프로그래밍 입문 3

Monadic Evaluatoreval :: (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)

Page 13: 하스켈 프로그래밍 입문 3

변종 0: Basic Evaluator

newtype M a = I a

instance Monad M where

return a = I a

(I a) >>= k = k a

Page 14: 하스켈 프로그래밍 입문 3

변종 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

Page 15: 하스켈 프로그래밍 입문 3

변종 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)

Page 16: 하스켈 프로그래밍 입문 3

변종 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)

Page 17: 하스켈 프로그래밍 입문 3

변종 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)

Page 18: 하스켈 프로그래밍 입문 3

변종 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, ())

Page 19: 하스켈 프로그래밍 입문 3

변종 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)

Page 20: 하스켈 프로그래밍 입문 3

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

Page 21: 하스켈 프로그래밍 입문 3

Functional Parser

Page 22: 하스켈 프로그래밍 입문 3

출처 : http://www.willamette.edu/~fruehr/haskell/seuss.html

Page 23: 하스켈 프로그래밍 입문 3

Parsernewtype Parser a = Parser (String -> [a, String])

• empty 리스트는 실패 , 아니면 성공• (a, s) 에서 a 는 파싱한 결과 s 는 파싱하고 남은 문자열• 리스트를 리턴하여 ambiguous grammar 처리

Page 24: 하스켈 프로그래밍 입문 3

item

• 문자열이 empty 가 아니면 첫 번째 문자를 리턴• empty 이면 에러

item :: Parser Char

item = Parser (\cs -> case cs of

"" -> []

(c:cs) -> [(c, cs)])

Page 25: 하스켈 프로그래밍 입문 3

모나드 정의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

Page 26: 하스켈 프로그래밍 입문 3

모나드 법칙1. return a >> f = f a

2. p >>= return = p

3. p >>= (\a -> (f a) >>= g)) = (p >>= (\a -> f a)) >>= g

Page 27: 하스켈 프로그래밍 입문 3

Do 표기법p1 >>= \a1 ->

p2 >>= \a2 ->

pn >>= \an ->

f a1 a2 … an

do a1 <- p1

a2 <- p2

an <- pn

f a1 a2 … an

Page 28: 하스켈 프로그래밍 입문 3

Do 표기법 사용 예제p :: Parser (Char, Char)

p = do c <- item

item

d <- item

return (c, d)

Page 29: 하스켈 프로그래밍 입문 3

MonadZero, MonadPlus

class Monad m => MonadZero m where

zero :: m a

class MonadZero m => MonadPlus m where

(++) :: m a -> m a -> m a

Page 30: 하스켈 프로그래밍 입문 3

Choice Operatorinstance MonadZero Parser where

zero = Parser (\cs -> [])

instance MonadPlus Parser where

p ++ q = (Parser (\cs ->

parse p cs ++ parse q cs))

Page 31: 하스켈 프로그래밍 입문 3

법칙• 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)

Page 32: 하스켈 프로그래밍 입문 3

Deterministic Choice Operator

(+++) :: Parser a -> Parser a -> Parser a

p +++ q = Parser (\cs -> case parse (p ++ q) of

[] -> []

(x:xs) -> [x])

Page 33: 하스켈 프로그래밍 입문 3

Conditional Parsingsat :: (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 ==)

Page 34: 하스켈 프로그래밍 입문 3

재귀 Combinatorstring :: String -> Parser String

string "" = return ""

string (c:cs) = do char c

string cs

return (c:cs)

Page 35: 하스켈 프로그래밍 입문 3

재귀 Combinatormany :: 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)

Page 36: 하스켈 프로그래밍 입문 3

재귀 Combinatorsepby :: 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)

Page 37: 하스켈 프로그래밍 입문 3

재귀 Combinatorchainl :: 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

Page 38: 하스켈 프로그래밍 입문 3

Lexical Combinatorsspace :: Parser String

space = many (sat isSpace)

token :: Parser a -> Parser a

token p = do a <- p

space

return a

Page 39: 하스켈 프로그래밍 입문 3

Lexical Combinatorssymb :: String -> Parser String

symb cs = token (string cs)

apply :: Parser a -> String -> [(a, String)]

apply p = parse (do {space; p})

Page 40: 하스켈 프로그래밍 입문 3

Expression Grammar• expr ::= expr addop term | term

• term ::= term mulop factor | factor

• factor ::= digit | (expr)

• digit ::= 0 | 1 | … | 9

• addop ::= + | -

• mulop ::= * | /

Page 41: 하스켈 프로그래밍 입문 3

Expression Parserexpr :: Parser Int

addop :: Parser (Int -> Int -> Int)

mulop :: Parser (Int -> Int -> Int)

expr = term `chainl1` addop

term = factor `chainl1` mulop

factor = digit +++ do { symb "("; n <- expr; symb ")"; return n }

digit = do { x <- token (sat isDigit); return (ord x - ord ‘0’)}

addop = do { symb "+"; return (+)} +++ do {symb "-"; return (-)}

mulop = do { symb "*"; return (*)} +++ do {symb "/"; return (div)}

Page 42: 하스켈 프로그래밍 입문 3

Expression Parser

> apply expr " 1 - 2 * 3 + 4 "

[(-1, "")]

Page 43: 하스켈 프로그래밍 입문 3

Library

1. parsec

2. megaparsec

3. attoparsec

Page 44: 하스켈 프로그래밍 입문 3

Zipper

Page 45: 하스켈 프로그래밍 입문 3

Tree

data Tree a = Empty

| Node a (Tree a) (Tree a)

deriving (Show)

Page 46: 하스켈 프로그래밍 입문 3

freeTree

출처 : http://learnyouahaskell.com/zippers

Page 47: 하스켈 프로그래밍 입문 3

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)

Page 48: 하스켈 프로그래밍 입문 3

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

Page 49: 하스켈 프로그래밍 입문 3

elementelemAt :: Directions -> Tree a -> a

elemAt (L:ds) (Node _ l _) = elemAt ds l

elemAt (R:ds) (Node _ _ r) = elemAt ds r

elemAt [] (Node x _ _) = x

Page 50: 하스켈 프로그래밍 입문 3

예제> let newTree = changeToP [R,L] freeTree

> elemAt [R,L] newTree

'P'

Page 51: 하스켈 프로그래밍 입문 3

Breadcrumbstype Breadcrumbs = [Direction]

goLeft :: (Tree a, Breadcrumbs) -> (Tree a, Breadcrumbs)

goLeft (Node _ l _, bs) = (l, L:bs)

goRight :: (Tree a, Breadcrumbs) -> (Tree a, Breadcrumbs)

goRight (Node _ _ r, bs) = (r, R:bs)

Page 52: 하스켈 프로그래밍 입문 3

Breadcrumbs> goLeft (goRight (freeTree, []))

(Node 'W' (Node 'C' Empty Empty) (Node 'R' Empty Empty),[L,R])

Page 53: 하스켈 프로그래밍 입문 3

Zipper 정의data Crumb a =

LeftCrumb a (Tree a)

| RightCrumb a (Tree a)

deriving (Show)

type Breadcrumbs a = [Crumb a]

Page 54: 하스켈 프로그래밍 입문 3

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)

Page 55: 하스켈 프로그래밍 입문 3

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)

Page 56: 하스켈 프로그래밍 입문 3

Zipper 정의

type Zipper a = (Tree a, Breadcrumbs a)

Page 57: 하스켈 프로그래밍 입문 3

Zipper 함수modify :: (a -> a)

-> Zipper a

-> Zipper a

modify f (Node x l r, bs) =

(Node (f x) l r, bs)

modify f (Empty, bs) = (Empty, bs)

Page 58: 하스켈 프로그래밍 입문 3

Zipper 함수topMost :: Zipper a -> Zipper a

topMost (t,[]) = (t,[])

topMost z = topMost (goUp z)

Page 59: 하스켈 프로그래밍 입문 3

Zipper 사용 예> let newFocus = modify (\_ -> 'P') (goRight (goLeft (freeTree,[])))

> let newFocus2 = modify (\_ -> 'X') (goUp newFocus)

Page 60: 하스켈 프로그래밍 입문 3

리스트data List a =

Empty

| Cons a (List a)

deriving (Show, Read, Eq, Ord)

Page 61: 하스켈 프로그래밍 입문 3

리스트 Zipper 의 정의

type ListZipper a = ([a],[a])

Page 62: 하스켈 프로그래밍 입문 3

리스트 Zipper 함수goForward :: ListZipper a -> ListZipper a

goForward (x:xs, bs) = (xs, x:bs)

goBack :: ListZipper a -> ListZipper a

goBack (xs, b:bs) = (b:xs, bs)

Page 63: 하스켈 프로그래밍 입문 3

리스트 Zipper 사용 예> let xs = [1,2,3,4]

> goForward (xs,[])

([2,3,4],[1])

> goForward ([2,3,4],[1])

([3,4],[2,1])

> goForward ([3,4],[2,1])

([4],[3,2,1])

> goBack ([4],[3,2,1])

([3,4],[2,1])

Page 64: 하스켈 프로그래밍 입문 3

참고 자료1. Monads for functional programming

• http://homepages.inf.ed.ac.uk/wadler/papers/marktoberdorf/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