src/Data/Machine/Stack.hs

{-# LANGUAGE GADTs #-}
{-# LANGUAGE Rank2Types #-}
-----------------------------------------------------------------------------
-- |
-- Module : Data.Machine.Stack
-- Copyright : (C) 2012 Edward Kmett
-- License : BSD-style (see the file LICENSE)
--
-- Maintainer : Edward Kmett <ekmett@gmail.com>
-- Stability : provisional
-- Portability : GADTs
--
----------------------------------------------------------------------------
module Data.Machine.Stack
 ( Stack(..)
 , stack
 , peek
 , pop
 , push
 ) where

import Data.Machine.Plan
import Data.Machine.Type

-- | This is a simple process type that knows how to push back input.
data Stack a r where
 Push :: a -> Stack a ()
 Pop :: Stack a a

-- | Peek at the next value in the input stream without consuming it
peek :: Plan (Stack a) b a
peek = do
 a <- pop
 push a
 return a

-- | Push back into the input stream
push :: a -> Plan (Stack a) b ()
push a = awaits (Push a)

-- | Pop the next value in the input stream
pop :: Plan (Stack a) b a
pop = awaits Pop

-- TODO: make this a class?

-- | Stream outputs from one 'Machine' into another with the possibility
-- of pushing inputs back.
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))

AltStyle によって変換されたページ (->オリジナル) /