packages feed

pandora-0.2.2: Pandora/Paradigm/Basis/Free.hs

module Pandora.Paradigm.Basis.Free (Free (..)) where

import Pandora.Core.Functor (type (:.), type (:=))
import Pandora.Pattern.Functor.Covariant (Covariant ((<$>), (<$$>)))
import Pandora.Pattern.Functor.Avoidable (Avoidable (empty))
import Pandora.Pattern.Functor.Pointable (Pointable (point))
import Pandora.Pattern.Functor.Alternative (Alternative ((<+>)))
import Pandora.Pattern.Functor.Applicative (Applicative ((<*>)))
import Pandora.Pattern.Functor.Traversable (Traversable ((->>), (->>>)))
import Pandora.Pattern.Functor.Bindable (Bindable ((>>=)))
import Pandora.Pattern.Functor.Liftable (Liftable (lift))
import Pandora.Pattern.Functor.Divariant (($))

data Free t a = Pure a | Impure (t :. Free t := a)

instance Covariant t => Covariant (Free t) where
	f <$> Pure x = Pure $ f x
	f <$> Impure xs = Impure $ f <$$> xs

instance Covariant t => Pointable (Free t) where
	point = Pure

instance Alternative t => Alternative (Free t) where
	Pure x <+> _ = Pure x
	_ <+> Pure y = Pure y
	Impure xs <+> Impure ys = Impure $ xs <+> ys

instance Avoidable t => Avoidable (Free t) where
	empty = Impure empty

instance Covariant t => Applicative (Free t) where
	Pure f <*> Pure y = Pure $ f y
	Pure f <*> Impure y = Impure $ f <$$> y
	Impure f <*> y = Impure $ (<*> y) <$> f

instance Covariant t => Bindable (Free t) where
	Pure x >>= f = f x
	Impure xs >>= f = Impure $ (>>= f) <$> xs

instance Traversable t => Traversable (Free t) where
	Pure x ->> f = Pure <$> f x
	Impure xs ->> f = Impure <$> xs ->>> f

instance Liftable Free where
	lift x = Impure $ Pure <$> x