Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Stateをさわってみる

pnlybubbles
September 17, 2017

 Stateをさわってみる

haskellのStateモナドへの理解を深めるために、Stateモナドを真似て実装をなぞりつつ気づいたことをまとめたお話になります。

スライド中で紹介している実装はこちら:
https://github.com/pnlybubbles-gomibako/counter-haskell

pnlybubbles

September 17, 2017
Tweet

More Decks by pnlybubbles

Other Decks in Programming

Transcript

  1. Who am I … • ΆΜΓ͌ • Twitter: @pn1y •

    ෺ཧֶՊ 3೥ • Web԰΍ͬͯ·͢ • ਺ֶŷţƄŜŢŘ…
  2. Stack type Stack = [Integer] push :: Integer -> Stack

    -> (Integer, Stack) push c cs = (c, c:cs) pop :: Stack -> (Integer, Stack) pop (c:cs) = (c, cs) ݹ͍Stack ৽͍͠Stack ݹ͍Stack ৽͍͠Stack Ҿ਺Ͱલͷ”ঢ়ଶ”Λ༩͑ɺ࣍ͷ”ঢ়ଶ”Λ࡞Δ
  3. Stackʹର͢Δجຊతͳૢ࡞ push :: Integer -> Stack -> (Integer, Stack) ݹ͍Stack

    (ૢ࡞ͷ݁Ռ, ৽͍͠Stack) ͜ͷૢ࡞ΛStackʹର͢Δ”ঢ়ଶͷߋ৽”ͱ͢Δ
  4. Stackͷίʔυશମ type Stack = [Integer] push :: Integer -> Stack

    -> (Integer, Stack) push c cs = (c, c:cs) pop :: Stack -> (Integer, Stack) pop (c:cs) = (c, cs) main = do let stack = [1, 2, 3, 4, 5] let (i1, stack1) = pop stack let (i2, stack2) = pop stack1 let (i3, stack3) = push (i1 + i2) stack2 print (i3, stack3)
  5. 2ͭpopͯ͠଍͠ࢉͯ͠push type Stack = [Integer] calc :: (Integer -> Integer

    -> Integer) -> Stack -> (Integer, Stack) calc op stack = (i3, stack3) where (i1, stack1) = pop stack (i2, stack2) = pop stack1 (i3, stack3) = push (op i1 i2) stack2 main = do let stack = [1, 2, 3, 4, 5] print $ calc (+) stack
  6. ͳΜ͔ඒ͘͠ͳ͍ͱ͜Ζ main = do let stack = [1, 2, 3,

    4, 5] let (i1, stack1) = pop stack let (i2, stack2) = pop stack1 print (i2, stack2) ࣍ͷૢ࡞Λ͢ΔͨΊʹ͸લͷঢ়ଶΛ৯Θͤͳ͍ͱ͍͚ͳ͍
  7. લͷૢ࡞ͱ࣍ͷૢ࡞Λܨ͙ bind :: (Stack -> (Integer, Stack)) -> (Integer ->

    (Stack -> (Integer, Stack))) -> (Stack -> (Integer, Stack)) લͷૢ࡞ ࣍ͷૢ࡞ લͷૢ࡞ͱ࣍ͷૢ࡞Λ࿈࠯ͤͨ͞ૢ࡞
  8. લͷૢ࡞ͱ࣍ͷૢ࡞Λܨ͙ bind :: (Stack -> (Integer, Stack)) -> (Integer ->

    (Stack -> (Integer, Stack))) -> (Stack -> (Integer, Stack)) લͷૢ࡞ͷ݁Ռ લͷૢ࡞ͷ݁ՌΛࡐྉʹɺ࣍ͷૢ࡞Λ࡞Δ
  9. bindͷ࣮૷ bind method lambda stack = (i', s') where (i,

    s) = method stack (i', s') = lambda i s લͷૢ࡞Λద༻ ࣍ͷૢ࡞Λద༻ ݁Ռ͔Β࣍ͷૢ࡞Λ࡞Δؔ਺
  10. calcΛbindͰॻ͖׵͑Δ calc op stack = (i3, stack3) where (i1, stack1)

    = pop stack (i2, stack2) = pop stack1 (i3, stack3) = push (op i1 i2) stack2 calc op = pop `bind` \i1 -> pop `bind` \i2 -> push (op i1 i2) calc :: (Integer -> Integer -> Integer) -> Stack -> (Integer, Stack) εοΩϦ😁
  11. ͳʹ΋͠ͳ͍ૢ࡞ unit :: Integer -> Stack -> (Integer, Stack) unit

    i cs = (i, cs) ͦͷ··ฦ͢ ͳʹ͔Λड͚औͬͯ ”ͳʹ΋͠ͳ͍ૢ࡞”ͷ݁Ռͱͯ͠٧ΊࠐΉ Stackͷૢ࡞
  12. 2ͭpopͯ͠଍͠ࢉ͢Δ͚ͩ calc op = pop `bind` \i1 -> pop `bind`

    \i2 -> unit (op i1 i2) calc :: (Integer -> Integer -> Integer) -> Stack -> (Integer, Stack) push͠ͳ͍Α calc op = pop `bind` \i1 -> pop `bind` \i2 -> push (op i1 i2) ݁ՌΛpushͯ͠Δ ଍͠ࢉͷ݁ՌΛฦ͢ ൺֱ
  13. Stackͷૢ࡞ͷܕΛ੔ཧ type StackOp = Stack -> (Integer, Stack) Stackͷૢ࡞ push

    :: Integer -> StackOp push :: StackOp calc :: (Integer -> Integer -> Integer) -> StackOp
  14. Stackͷૢ࡞ͷܕΛ੔ཧ unit :: Integer -> StackOp bind :: StackOp ->

    (Integer -> StackOp) -> StackOp bind_ :: StackOp -> StackOp -> StackOp ɾલͷ݁ՌΛࣺͯͯ࣍ͷૢ࡞ͱܨ͙ ɾલͷ݁ՌΛݩʹ࣍ͷૢ࡞ͱܨ͙ ɾ͋Δ݁ՌΛฦ͢Կ΋͠ͳ͍ૢ࡞Λ࡞Δ
  15. ॏཁͳͷ͸ίί main = do let stack = [1, 2, 3,

    4, 5] print $ (pop `bind` \i1 -> pop `bind` \i2 -> unit $ i1 + i2) $ stack ෳ਺ͷૢ࡞(pop, push)ΛॱংΛ࣮࣋ͬͯߦ͢Δ Α͏ʹͭͳ͗߹Θ͍ͤͯΔ
  16. ࣍ͷҰา newtype Stack a = Stack [a] deriving Show newtype

    StackOp a b = StackOp { run :: Stack a -> (b, Stack a) } ܕͷҰൠԽ https://github.com/pnlybubbles-gomibako/counter-haskell/blob/master/stack7.hs class MyMonad m where bind :: m b -> (b -> m c) -> m c bind_ :: m b -> m c -> m c unit :: b -> m b Ϟφυ(ͷΑ͏ͳ΋ͷ)
  17. StateϞφυΛ࢖ͬͯΈΔ import Control.Monad.State newtype Stack a = Stack [a] deriving

    Show type StackOp a b = State (Stack a) b https://github.com/pnlybubbles-gomibako/counter-haskell/blob/master/stack8.hs push :: a -> StackOp a a push c = get >>= \(Stack cs) -> put (Stack (c:cs)) >> return c
  18. doه๏Λ࢖ͬͯΈΔ https://github.com/pnlybubbles-gomibako/counter-haskell/blob/master/stack9.hs push :: a -> StackOp a a push

    c = get >>= \(Stack cs) -> put (Stack (c:cs)) >> return c push :: a -> StackOp a a push c = do (Stack cs) <- get put (Stack (c:cs)) return c