{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE QuantifiedConstraints #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -Wall -Wno-name-shadowing #-}
module Data.IFunctor.IFree
( IFree (..)
) where
import Data.IFunctor (IFunctor (..))
import Data.IFunctor.Classes
import Data.IMonad (IMonad (..))
import Data.ITraversable (ITraversable (..))
import Data.Typeable (Typeable)
import GHC.Generics (Generic, Generic1)
import Singlethongs (SingI)
import Text.Read
-- | Free IMonad
data IFree f a ix = IPure (a ix)
| IFree (f (IFree f a) ix)
deriving (Typeable, Generic, Generic1)
instance IFunctor f => IFunctor (IFree f) where
imap f (IPure x) = IPure (f x)
imap f (IFree x) = IFree (imap (imap f) x)
instance ITraversable f => ITraversable (IFree f) where
itraverse f (IPure x) = IPure <$> f x
itraverse f (IFree x) = IFree <$> itraverse (itraverse f) x
instance IFunctor f => IMonad (IFree f) where
ipure = IPure
ijoin (IPure x) = x
ijoin (IFree x) = IFree $ imap ijoin x
ibind f (IPure x) = f x
ibind f (IFree x) = IFree $ imap (ibind f) x
instance IShow f => IShow (IFree f) where
ishowsPrec sp p (IPure x) = showParen (p > 10) $
showString "IPure " . sp 11 x
ishowsPrec sp p (IFree x) = showParen (p > 10) $
showString "IFree " . (ishowsPrec (ishowsPrec sp)) 11 x
instance IRead f => IRead (IFree f) where
ireadPrec rp = parens $
(prec 10 $ do
Ident "IPure" <- lexP
x <- step rp
pure $ IPure x
)
+++
(prec 10 $ do
Ident "IFree" <- lexP
x <- step (ireadPrec (ireadPrec rp))
pure $ IFree x
)
instance IEq f => IEq (IFree f) where
ieq eq (IPure x) (IPure y) = eq x y
ieq eq (IFree x) (IFree y) = ieq (ieq eq) x y
ieq _ _ _ = False
instance IOrd f => IOrd (IFree f) where
icompare comp (IPure x) (IPure y) = comp x y
icompare comp (IFree x) (IFree y) = icompare (icompare comp) x y
icompare _ (IPure _) (IFree _) = LT
icompare _ (IFree _) (IPure _) = GT
instance (IShow f, IShow2 a, SingI ix) => Show (IFree f a ix) where
showsPrec = ishowsPrec1
instance (IRead f, IRead2 a, SingI ix) => Read (IFree f a ix) where
readPrec = ireadPrec1
instance (IEq f, IEq2 a, SingI ix) => Eq (IFree f a ix) where
(==) = ieq1
instance (IOrd f, IOrd2 a, SingI ix) => Ord (IFree f a ix) where
compare = icompare1