module Stack where

import StateFunc

type Stack a = [a]

push_ :: a -> Stack a -> Stack a         -- first version
push  :: a -> Stack a -> ((), Stack a)
pop   :: Stack a -> (a, Stack a)

push_ a as = a:as
push a as  = ((), a:as)
pop (a:as) = (a, as)

testStack_ :: Stack Int -> (Int, Stack Int)
testStack_ s0 =
  let
    s1 = push_ 0 s0
    s2 = push_ 1 s1
    s3 = push_ 2 s2
    s4 = push_ 3 s3
    (a,s5) = pop s4
    (b,s6) = pop s5
    s7 = push_ (a+b) s6
  in
    pop s7

testStack :: Stack Int -> (Int, Stack Int)
testStack s0 =
  let
    (_,s1) = push 0     s0
    (_,s2) = push 1     s1
    (_,s3) = push 2     s2
    (_,s4) = push 3     s3
    (a,s5) = pop        s4
    (b,s6) = pop        s5
    (_,s7) = push (a+b) s6
  in
    pop s7

------------------------------------------------------------------------------

pop'  :: StateFunc (Stack a) a
push' :: a -> StateFunc (Stack a) ()

pop'    = StateFunc $ \(a:as) -> (a,as)
push' a = StateFunc $ \as -> ((), a:as)

testStack' :: StateFunc (Stack Int) Int
testStack' = do
  push' 0
  push' 1
  push' 2
  push' 3
  a <- pop'
  b <- pop'
  push' (a+b)
  pop'
