{-#LANGUAGE TypeOperators, MultiParamTypeClasses, FlexibleInstances, FlexibleContexts, IncoherentInstances, UndecidableInstances, ScopedTypeVariables #-}
-----------------------------------------------------------------------------
--
-- Module      :  Base.Expr
-- Copyright   :
-- License     :  AllRightsReserved
--
-- Maintainer  :
-- Stability   :
-- Portability :
--
-- |
--
-----------------------------------------------------------------------------

module Base.Expr where

-- defining the expression

data Expr f = In {out :: f (Expr f) }

-- base expressions

data Val e = Val Int

data Add e = Add e e

-- co product

data (f :+: g) e = Inl (f e) | Inr (g e)

-- some functor instances

instance Functor Val where
    fmap f (Val x) = Val x

instance Functor Add where
    fmap f (Add e1 e2) = Add (f e1) (f e2)

instance (Functor f, Functor g) => Functor (f :+: g) where
    fmap f (Inl e1) = Inl (fmap f e1)
    fmap f (Inr e2) = Inr (fmap f e2)

-- fold for expressions

foldExpr :: Functor f => (f a -> a) -> Expr f -> a
foldExpr f = f  .  fmap (foldExpr f)  .  out

