{-# OPTIONS_GHC -fglasgow-exts #-}
{-# LANGUAGE OverlappingInstances #-}

module Data.Has
  ( (:*:)(..)
  , Has(..)
  , upd
  ) where

infixr 5 :*:

data a :*: b = a :*: b
    deriving (Eq,Ord,Show,Read,Bounded)

class Has e s where
    inj :: e -> s -> s
    prj :: s -> e

instance Has e (e :*: r) where
    inj e ~(_ :*: r) = e :*: r
    prj   ~(e :*: _) = e

instance Has e r => Has e (b :*: r) where
    inj e ~(b :*: r) = b :*: inj e r
    prj   ~(b :*: r) = prj r

-- This instance is needed for last types of type lists such as T in
-- (T1 :*: T2 :*: T3 :*: T)
instance Has e e where
    inj e _ = e
    prj e   = e

upd :: (Has e s) => (e -> e) -> s -> s
upd f s = let e = prj s in inj (f e) s