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

module Base.Inject where

import Base.Expr


-- automating functor injections

class (Functor sub, Functor sup) => (:<:) sub sup where
    inj :: sub a -> sup a

-- basic instances

instance Functor f => (:<:) f f where
    inj = id

instance (Functor f, Functor g) => (:<:) f (f :+: g) where
    inj = Inl

instance (Functor f, Functor g, Functor h, (:<:) f g) => (:<:) f (h :+: g) where
    inj = Inr  .  inj

inject :: ((:<:) g f) => g (Expr f) -> Expr f
inject = In  .  inj

val :: ((:<:) Val f) => Int -> Expr f
val = inject  .  Val

infixl 6 `plus`

plus :: ((:<:) Add f) => Expr f -> Expr f -> Expr f
plus x y = inject (Add x y)
