{-# LANGUAGE OverlappingInstances, TypeOperators, FlexibleInstances #-}
module Test.IOSpec.Types
(
IOSpec(..)
, foldIOSpec
, (:+:)(..)
, (:<:)
, inject
) where
import Control.Monad (ap)
data IOSpec f a =
Pure a
| Impure (f (IOSpec f a))
instance (Functor f) => Functor (IOSpec f) where
fmap f (Pure x) = Pure (f x)
fmap f (Impure t) = Impure (fmap (fmap f) t)
instance (Functor f) => Applicative (IOSpec f) where
pure = Pure
(<*>) = ap
instance (Functor f) => Monad (IOSpec f) where
return = Pure
(Pure x) >>= f = f x
(Impure t) >>= f = Impure (fmap (>>= f) t)
foldIOSpec :: Functor f => (a -> b) -> (f b -> b) -> IOSpec f a -> b
foldIOSpec pure _ (Pure x) = pure x
foldIOSpec pure impure (Impure t) = impure (fmap (foldIOSpec pure impure) t)
data (f :+: g) x = Inl (f x) | Inr (g x)
infixr 5 :+:
instance (Functor f, Functor g) => Functor (f :+: g) where
fmap f (Inl x) = Inl (fmap f x)
fmap f (Inr y) = Inr (fmap f y)
class (Functor sub, Functor sup) => sub :<: sup where
inj :: sub a -> sup a
instance Functor f => (:<:) f f where
inj = id
instance (Functor f, Functor g) => (:<:) f (f :+: g) where
inj = Inl
instance ((:<:) f g, Functor f, Functor g, Functor h)
=> (:<:) f (h :+: g) where
inj = Inr . inj
inject :: (g :<: f) => g (IOSpec f a) -> IOSpec f a
inject = Impure . inj