{-# LANGUAGE GADTs #-}
{-# LANGUAGE Rank2Types #-}
module Data.Machine.Stack
( Stack(..)
, stack
, peek
, pop
, push
) where
import Data.Machine.Plan
import Data.Machine.Type
data Stack a r where
Push :: a -> Stack a ()
Pop :: Stack a a
peek :: Plan (Stack a) b a
peek = do
a <- pop
push a
return a
{-# INLINABLE peek #-}
push :: a -> Plan (Stack a) b ()
push a = awaits (Push a)
{-# INLINABLE push #-}
pop :: Plan (Stack a) b a
pop = awaits Pop
{-# INLINABLE pop #-}
stack :: Monad m => MachineT m k a -> MachineT m (Stack a) o -> MachineT m k o
stack up down =
stepMachine down $ \stepD ->
case stepD of
Stop -> stopped
Yield o down' -> encased (Yield o (up `stack` down'))
Await down' (Push a) _ -> encased (Yield a up) `stack` down' ()
Await down' Pop ffD ->
stepMachine up $ \stepU ->
case stepU of
Stop -> stopped `stack` ffD
Yield o up' -> up' `stack` down' o
Await up' req ffU -> encased (Await (\a -> up' a `stack` encased stepD) req
( ffU `stack` encased stepD))
{-# INLINABLE stack #-}