{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, UndecidableInstances #-} {- | /RECOMMENDATION:/ Use "Data.Generics.Uniplate.Data" instead - it usually performs faster (sometimes significantly so) and requires no special instance declarations. This module supplies a method for writing 'Uniplate' / 'Biplate' instances. One instance declaration is required for each data type you wish to work with. The instances can be generated using Derive: <http://community.haskell.org/~ndm/derive/>. To take an example: > data Expr = Var Int | Neg Expr | Add Expr Expr > deriving Typeable > > instance (Typeable a, Uniplate a) => PlateAll Expr a where > plateAll (Var x ) = plate Var |+ x > plateAll (Neg x ) = plate Neg |+ x > plateAll (Add x y) = plate Add |+ x |+ y -} module Data.Generics.Uniplate.Typeable( module Data.Generics.Uniplate.Operations, module Data.Typeable, -- * The Class PlateAll(..), -- * The Combinators plate, (|+), (|-), plateProject ) where import Control.Arrow import Data.Generics.Uniplate.Operations import Data.Generics.Uniplate.Internal.Utils import Data.Generics.Str import Data.Typeable import Data.Ratio instance (Typeable a, Typeable b, Uniplate b, PlateAll a b) => Biplate a b where biplate = plateMore instance PlateAll a a => Uniplate a where uniplate = plateAll type Type from to = (Str to, Str to -> from) plateMore :: (Typeable from, Typeable to, PlateAll from to) => from -> Type from to plateMore x = res where res = case asTypeOf (cast x) (Just $ strType $ fst res) of Nothing -> plateAll x Just y -> (One y, \(One y) -> unsafeCoerce y) -- | This class should be defined for each data type of interest. class PlateAll from to where -- | This method should be defined using 'plate' and '|+', '|-'. plateAll :: from -> Type from to -- | The main combinator used to start the chain. plate :: from -> Type from to plate x = (Zero, \_ -> x) -- | The field to the right may contain the target. (|+) :: (Typeable item, Typeable to, PlateAll item to) => Type (item -> from) to -> item -> Type from to (|+) (xs,x_) y = case plateMore y of (ys,y_) -> (Two xs ys,\(Two xs ys) -> x_ xs (y_ ys)) -- | The field to the right /does not/ contain the target. -- This can be used as either an optimisation, or more commonly for excluding -- primitives such as Int. (|-) :: Type (item -> from) to -> item -> Type from to (|-) (xs,x_) y = (xs,\xs -> x_ xs y) -- | Write an instance in terms of a projection/injection pair. Usually used to define instances -- for abstract containers such as Map: -- -- > instance (Ord a, Typeable a, PlateAll a c, Typeable b, PlateAll b c, -- > Typeable c, PlateAll c c) => PlateAll (Map.Map a b) c where -- > plateAll = plateProject Map.toList Map.fromList plateProject :: (Typeable item, Typeable to, PlateAll item to) => (from -> item) -> (item -> from) -> from -> Type from to plateProject into outof = second (outof . ) . plateAll . into -- * Instances -- ** Primitive Types instance PlateAll Int to where plateAll x = plate x instance PlateAll Bool to where plateAll x = plate x instance PlateAll Char to where plateAll x = plate x instance PlateAll Integer to where plateAll x = plate x instance PlateAll Double to where plateAll x = plate x instance PlateAll Float to where plateAll x = plate x instance PlateAll () to where plateAll x = plate x -- ** Container Types instance (PlateAll from to, Typeable from, Typeable to, Uniplate to) => PlateAll [from] to where plateAll [] = plate [] plateAll (x:xs) = plate (:) |+ x |+ xs instance (PlateAll from to, Typeable from, Typeable to, Uniplate to) => PlateAll (Maybe from) to where plateAll Nothing = plate Nothing plateAll (Just x) = plate Just |+ x instance (PlateAll a to, Typeable a, PlateAll b to, Typeable b, Typeable to, Uniplate to) => PlateAll (Either a b) to where plateAll (Left x) = plate Left |+ x plateAll (Right x) = plate Right |+ x instance (PlateAll a to, Typeable a ,PlateAll b to, Typeable b ,Typeable to, Uniplate to) => PlateAll (a,b) to where plateAll (a,b) = plate (,) |+ a |+ b instance (PlateAll a to, Typeable a ,PlateAll b to, Typeable b ,PlateAll c to, Typeable c ,Typeable to, Uniplate to) => PlateAll (a,b,c) to where plateAll (a,b,c) = plate (,,) |+ a |+ b |+ c instance (PlateAll a to, Typeable a ,PlateAll b to, Typeable b ,PlateAll c to, Typeable c ,PlateAll d to, Typeable d ,Typeable to, Uniplate to) => PlateAll (a,b,c,d) to where plateAll (a,b,c,d) = plate (,,,) |+ a |+ b |+ c |+ d instance (PlateAll a to, Typeable a ,PlateAll b to, Typeable b ,PlateAll c to, Typeable c ,PlateAll d to, Typeable d ,PlateAll e to, Typeable e ,Typeable to, Uniplate to) => PlateAll (a,b,c,d,e) to where plateAll (a,b,c,d,e) = plate (,,,,) |+ a |+ b |+ c |+ d |+ e instance (Integral a, PlateAll a to, Typeable a, Typeable to, Uniplate to) => PlateAll (Ratio a) to where plateAll = plateProject (\x -> (numerator x, denominator x)) (uncurry (%))