{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE OverlappingInstances #-} ----------------------------------------------------------------------------- -- | -- Module : Generics.EMGM.Common.Base -- Copyright : (c) 2008 Universiteit Utrecht -- License : BSD3 -- -- Maintainer : generics@haskell.org -- Stability : experimental -- Portability : non-portable -- -- Summary: Type classes used for generic functions with /one/ generic argument. -- -- Generic functions using one generic argument are defined as instances of -- 'Generic'. This class contains all of the methods (called \"type cases\" in -- datatype-generic language) used to define the run-time type representation of -- a datatype. -- -- To simplify generic functions, we use type classes for representation -- dispatching. There are \"dispatchers\" for each category of function (see -- below) and each category has one \"Rep\" class. -- -- Some 'Generic'-based functions operate on monomorphic values (using 'Rep'). -- The functions included with the library are: -- -- * "Generics.EMGM.Functions.Collect" -- -- * "Generics.EMGM.Functions.Compare" -- -- * "Generics.EMGM.Functions.Enum" -- -- * "Generics.EMGM.Functions.Read" -- -- * "Generics.EMGM.Functions.Show" -- -- Other 'Generic'-based functions operate on types of the form @f a@ (using -- 'FRep') where @f@ is the actual generic argument (the one that needs a -- run-time representation). The functions included with the library are: -- -- * "Generics.EMGM.Functions.Crush" ----------------------------------------------------------------------------- module Generics.EMGM.Common.Base ( -- * Generic function class Generic(..), -- * Representation dispatcher classes Rep(..), FRep(..), ) where import Generics.EMGM.Common.Representation infixr 5 `rsum` infixr 6 `rprod` -- | This class forms the foundation for defining generic functions with a -- single generic argument. Each method represents a type case. The class -- includes cases for primitive types, cases for the structural representation, -- and the 'rtype' case for adding support for new datatypes. class Generic g where -- | Many functions perform the same operation on the non-structural cases (as -- well as 'Unit'). The cases for constant datatypes ('Int', 'Integer', -- 'Float', 'Double', 'Char', and 'Unit') have a default implementation of -- 'rconstant', thus a generic function may only override 'rconstant' if -- desired. Note that there is no default implementation for 'rconstant' -- itself. -- -- The class context represents the intersection set of supported type -- classes. rconstant :: (Enum a, Eq a, Ord a, Read a, Show a) => g a -- | Case for the primitive type 'Int'. (Default implementation: -- 'rconstant'.) rint :: g Int -- | Case for the primitive type 'Integer'. (Default implementation: -- 'rconstant'.) rinteger :: g Integer -- | Case for the primitive type 'Float'. (Default implementation: -- 'rconstant'.) rfloat :: g Float -- | Case for the primitive type 'Double'. (Default implementation: -- 'rconstant'.) rdouble :: g Double -- | Case for the primitive type 'Char'. (Default implementation: -- 'rconstant'.) rchar :: g Char -- | Case for the structural representation type 'Unit'. It is used to -- represent a constructor with no arguments. (Default implementation: -- 'rconstant'.) runit :: g Unit -- | Case for the structural representation type @:+:@ (sum). It -- is used to represent alternative choices between constructors. (No -- default implementation.) rsum :: g a -> g b -> g (a :+: b) -- | Case for the structural representation type @:*:@ (product). -- It is used to represent multiple arguments to a constructor. (No -- default implementation.) rprod :: g a -> g b -> g (a :*: b) -- | Case for constructors. While not necessary for every generic function, -- this method is required for 'Read' and 'Show'. It is used to hold the -- meta-information about a constructor ('ConDescr'), e.g. name, arity, -- fixity, etc. (Since most generic functions do not use 'rcon' and simply pass -- the value through, the default implementation is @const id@.) rcon :: ConDescr -> g a -> g a -- | Case for datatypes. This method is used to define the structural -- representation of an arbitrary Haskell datatype. The first argument is the -- embedding-projection pair, necessary for establishing the isomorphism -- between datatype and representation. The second argument is the -- run-time representation using the methods of 'Generic'. (No default -- implementation.) rtype :: EP b a -> g a -> g b rint = rconstant rinteger = rconstant rfloat = rconstant rdouble = rconstant rchar = rconstant runit = rconstant rcon = const id -- | The 'Generic' representation dispatcher for monomorphic types (kind @*@). -- Every structure type and supported datatype should have an instance of -- 'Rep'. (No default implementation.) class Rep g a where rep :: g a instance (Generic g) => Rep g Int where rep = rint instance (Generic g) => Rep g Integer where rep = rinteger instance (Generic g) => Rep g Float where rep = rfloat instance (Generic g) => Rep g Double where rep = rdouble instance (Generic g) => Rep g Char where rep = rchar instance (Generic g) => Rep g Unit where rep = runit instance (Generic g, Rep g a, Rep g b) => Rep g (a :+: b) where rep = rsum rep rep instance (Generic g, Rep g a, Rep g b) => Rep g (a :*: b) where rep = rprod rep rep -- | The 'Generic' representation dispatcher for functor types (kind @* -> *@), -- sometimes called container types. (No default implementation.) class FRep g f where frep :: g a -> g (f a)