-- | Module with basic infrastructure for function inheritance

--   based on open rercusion.

--

--   See the work of William Cook.

--

--   We use the following terminology.

--

--     * A /closed/ function is an ordinary function. 

--

--     * A /mixin/ function is an open function that can be

--       inherited from, or that extends another open function.

--

--   We obtain a closed function from a base mixin 'base'

--   and a number of mixin extensions 'e1',...,'en' as follows:

--

-- >  mixin (en <@> ... <@> e1 <@> base)

--  

module Control.Mixin.Mixin (

  Mixin,

  (<@>),

  mixin,

  mixinId,

  mixinLift

) where



infixl 5 <@>



-- | Type of mixin functions.

type Mixin a =  a -- the 'super' function

	     -> a -- the 'this'  function

	     -> a -- the current function



-- | Mixin composition.

(<@>) :: Mixin a -> Mixin a -> Mixin a

(f1 <@> f2) super this = f1 (f2 super this) this



-- | Turn a mixin into a closed function.

mixin :: Mixin a -> a

mixin openF 

  = let closedF = openF errorF closedF 

        errorF  = error $ "super called in base mixin"

    in closedF



-- | Mixin identity function.

--

-- Identity for mixin composition:

-- 

--   

-- > mixinId <@> f  ==  f

-- > f <@> mixinId  ==  f

--  

mixinId :: Mixin a

mixinId super this = super



-- | Mixin lift function

--

-- > mixin . mixinLift = id



mixinLift :: (a -> b) -> Mixin (a -> b)

mixinLift f _ _ = f