{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
module Control.FX.Monad.Data.Stack (
Stack(..)
, runStack
, Context(..)
, Input(..)
, Output(..)
) where
import Data.Typeable (Typeable, Proxy, typeOf)
import Control.FX
import Control.FX.Structure.Stack
import Control.FX.Monad.Data.Class
newtype Stack
(mark :: * -> *)
(f :: * -> *)
(d :: *)
(a :: *)
= Stack
{ unStack :: f d -> Pair (f d) a
} deriving (Typeable)
instance
( Typeable f, Typeable d, Typeable a, Typeable mark
) => Show (Stack mark f d a)
where
show
:: Stack mark f d a
-> String
show = show . typeOf
instance
( MonadIdentity mark
) => Functor (Stack mark f d)
where
fmap
:: (a -> b)
-> Stack mark f d a
-> Stack mark f d b
fmap f (Stack x) = Stack $ \s1 ->
let Pair s2 a = x s1 in
Pair s2 (f a)
instance
( MonadIdentity mark
) => Applicative (Stack mark f d)
where
pure
:: a
-> Stack mark f d a
pure a = Stack $ \s -> Pair s a
(<*>)
:: Stack mark f d (a -> b)
-> Stack mark f d a
-> Stack mark f d b
(Stack f') <*> (Stack x') = Stack $ \s1 ->
let Pair s2 f = f' s1 in
let Pair s3 x = x' s2 in
Pair s3 (f x)
instance
( MonadIdentity mark
) => Monad (Stack mark f d)
where
return
:: a
-> Stack mark f d a
return a = Stack $ \s -> Pair s a
(>>=)
:: Stack mark f d a
-> (a -> Stack mark f d b)
-> Stack mark f d b
(Stack x') >>= f = Stack $ \s1 ->
let Pair s2 x = x' s1 in
(unStack . f) x s2
instance
( Eq (f d), MonadIdentity mark
) => EqIn (Stack mark f d)
where
data Context (Stack mark f d)
= StackCtx
{ unStackCtx :: mark (f d)
} deriving (Typeable)
eqIn
:: (Eq a)
=> Context (Stack mark f d)
-> Stack mark f d a
-> Stack mark f d a
-> Bool
eqIn (StackCtx s) (Stack x) (Stack y) =
(x $ unwrap s) == (y $ unwrap s)
deriving instance
( Eq (mark (f d))
) => Eq (Context (Stack mark f d))
deriving instance
( Show (mark (f d))
) => Show (Context (Stack mark f d))
instance
( MonadIdentity mark
) => RunMonad (Stack mark f d)
where
data Input (Stack mark f d)
= StackIn
{ unStackIn :: mark (f d)
} deriving (Typeable)
data Output (Stack mark f d) a
= StackOut
{ unStackOut :: Pair (mark (f d)) a
} deriving (Typeable)
run
:: Input (Stack mark f d)
-> Stack mark f d a
-> Output (Stack mark f d) a
run (StackIn s) (Stack x) =
let Pair s1 a = x (unwrap s)
in StackOut $ Pair (return s1) a
deriving instance
( Eq (mark (f d))
) => Eq (Input (Stack mark f d))
deriving instance
( Show (mark (f d))
) => Show (Input (Stack mark f d))
deriving instance
( Eq (mark (f d)), Eq a
) => Eq (Output (Stack mark f d) a)
deriving instance
( Show (mark (f d)), Show a
) => Show (Output (Stack mark f d) a)
runStack
:: ( MonadIdentity mark, IsStack f )
=> f d
-> Stack mark f d a
-> Pair (mark (f d)) a
runStack s x = unStackOut $ run (StackIn $ pure s) x
instance
( MonadIdentity mark, IsStack f
) => MonadStack mark f d (Stack mark f d)
where
push
:: Proxy f
-> mark d
-> Stack mark f d ()
push _ x = Stack $ \s ->
Pair (stackPush (unwrap x) s) ()
pop
:: Proxy f
-> Stack mark f d (mark (Maybe d))
pop _ = Stack $ \s ->
case stackPop s of
Nothing ->
Pair s (pure Nothing)
Just (a,as) ->
Pair as (pure $ Just a)