{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FunctionalDependencies , UndecidableInstances #-} {-# OPTIONS_GHC -Wall #-} ---------------------------------------------------------------------- -- | -- Module : Shady.ITransform -- Copyright : (c) Conal Elliott 2009 -- License : AGPLv3 -- -- Maintainer : conal@conal.net -- Stability : experimental -- -- Invertible transformations ---------------------------------------------------------------------- module Shady.ITransform ( ITransform(..), inverse, andInverse , ITrans(..) ) where import Data.Monoid (Monoid(..)) import Control.Applicative (liftA2) import Shady.Misc import Shady.Complex (Complex) import Shady.Language.Exp -- | Transform with inverse. The 'Monoid' instances is identity and -- composition (in the usual order for composition of the forward -- transformations). data ITransform a = ITransform { itForward :: Unop a , itBackward :: Unop a } instance Monoid (ITransform a) where mempty = ITransform id id ITransform oF oB `mappend` ITransform iF iB = ITransform (oF.iF) (iB.oB) -- | Inverse an 'ITransform' inverse :: Unop (ITransform a) inverse (ITransform forw back) = ITransform back forw -- | Handy when we invert a transform by modifying the argument to the -- transform's maker. andInverse :: (c -> Unop a) -> (c -> c) -> c -> ITransform a andInverse f inva = liftA2 ITransform f (f.inva) infixr 1 *: -- | Transformable values class ITrans w a | a -> w where (*:) :: ITransform w -> Unop a -- Inert on our basic types instance ITrans w (E a) where (*:) = const id -- Typical identity instance: instance ITrans (Complex s) (Complex s) where (*:) = itForward -- Distribute over tuple types. instance (ITrans w a, ITrans w b) => ITrans w (a,b) where ix *: (a,b) = (ix *: a, ix *: b) instance (ITrans w a, ITrans w b, ITrans w c) => ITrans w (a,b,c) where ix *: (a,b,c) = (ix *: a, ix *: b, ix *: c) instance (ITrans w a, ITrans w b, ITrans w c, ITrans w d ) => ITrans w (a,b,c,d) where ix *: (a,b,c,d) = (ix *: a, ix *: b, ix *: c, ix *: d) -- Function is an interesting case. Inversely transform input. instance (ITrans w a, ITrans w b) => ITrans w (a -> b) where ix *: f = (*:) ix . f . (*:) (inverse ix) -- type Trans = forall a. ITrans w a => a -> a