1 -----------------------------------------------------------------------------
3 -- Module : Data.Generics.Basics
4 -- Copyright : (c) The University of Glasgow, CWI 2001--2004
5 -- License : BSD-style (see the file libraries/base/LICENSE)
7 -- Maintainer : libraries@haskell.org
8 -- Stability : experimental
9 -- Portability : non-portable
11 -- \"Scrap your boilerplate\" --- Generic programming in Haskell
12 -- See <http://www.cs.vu.nl/boilerplate/>. The present module provides
13 -- the Data class with its primitives for generic programming.
15 -----------------------------------------------------------------------------
17 module Data.Generics.Basics (
19 -- * Module Data.Typeable re-exported for convenience
22 -- * The Data class for processing constructor applications
24 gfoldl, -- :: ... -> a -> c a
25 toConstr, -- :: a -> Constr
26 fromConstr, -- :: Constr -> a
27 dataTypeOf, -- :: a -> DataType
28 dataCast1, -- mediate types and unary type constructors
29 dataCast2 -- mediate types and binary type constructors
32 -- * Datatype representations
33 DataType, -- abstract, instance of: Show
34 Constr, -- abstract, instance of: Eq, Show
35 DataRep(..), -- instance of: Eq, Show
36 ConstrRep(..), -- instance of: Eq, Show
37 ConIndex, -- alias for Int, start at 1
38 Fixity(..), -- instance of: Eq, Show
40 -- * Observers for datatype representations
41 dataTypeName, -- :: DataType -> String
42 dataTypeRep, -- :: DataType -> DataRep
43 constrType, -- :: Constr -> DataType
44 constrRep, -- :: Constr -> ConstrRep
45 repConstr, -- :: DataType -> ConstrRep -> Constr
47 -- * Representations of algebraic data types
48 mkDataType, -- :: String -> [Constr] -> DataType
49 mkConstr, -- :: DataType -> String -> Fixity -> Constr
50 dataTypeConstrs,-- :: DataType -> [Constr]
51 constrFields, -- :: Constr -> [String]
52 constrFixity, -- :: Constr -> Fixity
54 -- * From strings to constr's and vice versa: all data types
55 showConstr, -- :: Constr -> String
56 readConstr, -- :: DataType -> String -> Maybe Constr
58 -- * Convenience funtions: algebraic data types
59 isAlgType, -- :: DataType -> Bool
60 indexConstr, -- :: DataType -> ConIndex -> Constr
61 constrIndex, -- :: Constr -> ConIndex
62 maxConstrIndex, -- :: DataType -> ConIndex
64 -- * Representation of primitive types
65 mkIntType, -- :: String -> DataType
66 mkFloatType, -- :: String -> DataType
67 mkStringType, -- :: String -> DataType
68 mkIntConstr, -- :: DataType -> Integer -> Constr
69 mkFloatConstr, -- :: DataType -> Double -> Constr
70 mkStringConstr, -- :: DataType -> String -> Constr
72 -- * Non-representations for non-presentable types
73 mkNorepType, -- :: String -> DataType
74 isNorepType, -- :: DataType -> Bool
76 -- * Convenience functions: take type constructors apart
77 tyconUQname, -- :: String -> String
78 tyconModule, -- :: String -> String
80 -- * Generic maps defined in terms of gfoldl
93 ------------------------------------------------------------------------------
105 ------------------------------------------------------------------------------
109 ------------------------------------------------------------------------------
113 The Data class comprehends a fundamental primitive "gfoldl" for
114 folding over constructor applications, say terms. This primitive can
115 be instantiated in several ways to map over the immediate subterms of
116 a term; see the "gmap" combinators later in this module. Indeed, a
117 generic programmer does not necessarily need to use the ingenious
118 gfoldl primitive but rather the intuitive "gmap" combinators. The
119 "gfoldl" primitive is completed by means to query top-level
120 constructors, to turn constructor representations into proper terms,
121 and to list all possible datatype constructors. This completion
122 allows us to serve generic programming scenarios like read, show,
123 equality, term generation.
127 class Typeable a => Data a where
131 Folding constructor applications ("gfoldl")
133 The combinator takes two arguments "f" and "z" to fold over a term
134 "x". The result type is defined in terms of "x" but variability is
135 achieved by means of type constructor "c" for the construction of the
136 actual result type. The purpose of the argument "z" is to define how
137 the empty constructor application is folded. So "z" is like the
138 neutral / start element for list folding. The purpose of the argument
139 "f" is to define how the nonempty constructor application is
140 folded. That is, "f" takes the folded "tail" of the constructor
141 application and its head, i.e., an immediate subterm, and combines
142 them in some way. See the Data instances in this file for an
143 illustration of "gfoldl". Conclusion: the type of gfoldl is a
144 headache, but operationally it is simple generalisation of a list
149 -- | Left-associative fold operation for constructor applications
150 gfoldl :: (forall a b. Data a => c (a -> b) -> a -> c b)
151 -> (forall g. g -> c g)
154 -- Default definition for gfoldl
155 -- which copes immediately with basic datatypes
159 -- | Obtaining the constructor from a given datum.
160 -- For proper terms, this is meant to be the top-level constructor.
161 -- Primitive datatypes are here viewed as potentially infinite sets of
162 -- values (i.e., constructors).
164 toConstr :: a -> Constr
167 -- | Building a term from a constructor
168 fromConstr :: Constr -> a
171 -- | Provide access to list of all constructors
172 dataTypeOf :: a -> DataType
176 ------------------------------------------------------------------------------
178 -- Mediate types and type constructors
180 ------------------------------------------------------------------------------
182 -- | Mediate types and unary type constructors
183 dataCast1 :: Typeable1 t
184 => (forall a. Data a => c (t a))
186 dataCast1 _ = Nothing
188 -- | Mediate types and binary type constructors
189 dataCast2 :: Typeable2 t
190 => (forall a b. (Data a, Data b) => c (t a b))
192 dataCast2 _ = Nothing
196 ------------------------------------------------------------------------------
198 -- Typical generic maps defined in terms of gfoldl
200 ------------------------------------------------------------------------------
204 The combinators gmapT, gmapQ, gmapM, ... can all be defined in terms
205 of gfoldl. We provide corresponding default definitions leaving open
206 the opportunity to provide datatype-specific definitions.
208 (The inclusion of the gmap combinators as members of class Data allows
209 the programmer or the compiler to derive specialised, and maybe more
210 efficient code per datatype. Note: gfoldl is more higher-order than
211 the gmap combinators. This is subject to ongoing benchmarking
212 experiments. It might turn out that the gmap combinators will be moved
213 out of the class Data.)
215 Conceptually, the definition of the gmap combinators in terms of the
216 primitive gfoldl requires the identification of the gfoldl function
217 arguments. Technically, we also need to identify the type constructor
218 "c" for the construction of the result type from the folded term type.
223 -- | A generic transformation that maps over the immediate subterms
224 gmapT :: (forall b. Data b => b -> b) -> a -> a
226 -- Use an identity datatype constructor ID (see below)
227 -- to instantiate the type constructor c in the type of gfoldl,
228 -- and perform injections ID and projections unID accordingly.
230 gmapT f x = unID (gfoldl k ID x)
232 k (ID c) x = ID (c (f x))
235 -- | A generic query with a left-associative binary operator
236 gmapQl :: (r -> r' -> r) -> r -> (forall a. Data a => a -> r') -> a -> r
237 gmapQl o r f = unCONST . gfoldl k z
239 k c x = CONST $ (unCONST c) `o` f x
244 In the definition of gmapQ? combinators, we use phantom type
245 constructors for the "c" in the type of "gfoldl" because the result
246 type of a query does not involve the (polymorphic) type of the term
247 argument. In the definition of gmapQl we simply use the plain constant
248 type constructor because gfoldl is left-associative anyway and so it
249 is readily suited to fold a left-associative binary operation over the
250 immediate subterms. In the definition of gmapQr, extra effort is
251 needed. We use a higher-order accumulation trick to mediate between
252 left-associative constructor application vs. right-associative binary
253 operation (e.g., (:)). When the query is meant to compute a value of
254 type r, then the result type withing generic folding is r -> r. So the
255 result of folding is a function to which we finally pass the right
260 -- | A generic query with a right-associative binary operator
261 gmapQr :: (r' -> r -> r) -> r -> (forall a. Data a => a -> r') -> a -> r
262 gmapQr o r f x = unQr (gfoldl k (const (Qr id)) x) r
264 k (Qr c) x = Qr (\r -> c (f x `o` r))
267 -- | A generic query that processes the immediate subterms and returns a list
268 gmapQ :: (forall a. Data a => a -> u) -> a -> [u]
269 gmapQ f = gmapQr (:) [] f
272 -- | A generic query that processes one child by index (zero-based)
273 gmapQi :: Int -> (forall a. Data a => a -> u) -> a -> u
274 gmapQi i f x = case gfoldl k z x of { Qi _ q -> fromJust q }
276 k (Qi i' q) a = Qi (i'+1) (if i==i' then Just (f a) else q)
280 -- | A generic monadic transformation that maps over the immediate subterms
281 gmapM :: Monad m => (forall a. Data a => a -> m a) -> a -> m a
283 -- Use immediately the monad datatype constructor
284 -- to instantiate the type constructor c in the type of gfoldl,
285 -- so injection and projection is done by return and >>=.
287 gmapM f = gfoldl k return
294 -- | Transformation of at least one immediate subterm does not fail
295 gmapMp :: MonadPlus m => (forall a. Data a => a -> m a) -> a -> m a
299 The type constructor that we use here simply keeps track of the fact
300 if we already succeeded for an immediate subterm; see Mp below. To
301 this end, we couple the monadic computation with a Boolean.
305 gmapMp f x = unMp (gfoldl k z x) >>= \(x',b) ->
306 if b then return x' else mzero
308 z g = Mp (return (g,False))
310 = Mp ( c >>= \(h,b) ->
311 (f x >>= \x' -> return (h x',True))
312 `mplus` return (h x,b)
315 -- | Transformation of one immediate subterm with success
316 gmapMo :: MonadPlus m => (forall a. Data a => a -> m a) -> a -> m a
320 We use the same pairing trick as for gmapMp,
321 i.e., we use an extra Bool component to keep track of the
322 fact whether an immediate subterm was processed successfully.
323 However, we cut of mapping over subterms once a first subterm
324 was transformed successfully.
328 gmapMo f x = unMp (gfoldl k z x) >>= \(x',b) ->
329 if b then return x' else mzero
331 z g = Mp (return (g,False))
333 = Mp ( c >>= \(h,b) -> if b
335 else (f x >>= \x' -> return (h x',True))
336 `mplus` return (h x,b)
340 -- | The identity type constructor needed for the definition of gmapT
341 newtype ID x = ID { unID :: x }
344 -- | The constant type constructor needed for the definition of gmapQl
345 newtype CONST c a = CONST { unCONST :: c }
348 -- | Type constructor for adding counters to queries
349 data Qi q a = Qi Int (Maybe q)
352 -- | The type constructor used in definition of gmapQr
353 newtype Qr r a = Qr { unQr :: r -> r }
356 -- | The type constructor used in definition of gmapMp
357 newtype Mp m x = Mp { unMp :: m (x, Bool) }
361 ------------------------------------------------------------------------------
363 -- Datatype and constructor representations
365 ------------------------------------------------------------------------------
369 -- | Representation of datatypes.
370 -- | A package of constructor representations with names of type and module.
371 -- | The list of constructors could be an array, a balanced tree, or others.
373 data DataType = DataType
381 -- | Representation of constructors
383 { conrep :: ConstrRep
384 , constring :: String
385 , confields :: [String] -- for AlgRep only
386 , confixity :: Fixity -- for AlgRep only
387 , datatype :: DataType
390 instance Show Constr where
394 -- | Equality of constructors
395 instance Eq Constr where
396 c == c' = constrRep c == constrRep c'
399 -- | Public representation of datatypes
400 data DataRep = AlgRep [Constr]
409 -- | Public representation of constructors
410 data ConstrRep = AlgConstr ConIndex
413 | StringConstr String
419 -- | Unique index for datatype constructors.
420 -- | Textual order is respected. Starts at 1.
425 -- | Fixity of constructors
427 | Infix -- Later: add associativity and precedence
432 ------------------------------------------------------------------------------
434 -- Observers for datatype representations
436 ------------------------------------------------------------------------------
439 -- | Gets the type constructor including the module
440 dataTypeName :: DataType -> String
445 -- | Gets the public presentation of datatypes
446 dataTypeRep :: DataType -> DataRep
447 dataTypeRep = datarep
450 -- | Gets the datatype of a constructor
451 constrType :: Constr -> DataType
452 constrType = datatype
455 -- | Gets the public presentation of constructors
456 constrRep :: Constr -> ConstrRep
460 -- | Look up a constructor by its representation
461 repConstr :: DataType -> ConstrRep -> Constr
463 case (dataTypeRep dt, cr) of
464 (AlgRep cs, AlgConstr i) -> cs !! (i-1)
465 (IntRep, IntConstr i) -> mkIntConstr dt i
466 (FloatRep, FloatConstr f) -> mkFloatConstr dt f
467 (StringRep, StringConstr str) -> mkStringConstr dt str
468 _ -> error "repConstr"
472 ------------------------------------------------------------------------------
474 -- Representations of algebraic data types
476 ------------------------------------------------------------------------------
479 -- | Constructs an algebraic datatype
480 mkDataType :: String -> [Constr] -> DataType
481 mkDataType str cs = DataType
483 , datarep = AlgRep cs
487 -- | Constructs a constructor
488 mkConstr :: DataType -> String -> [String] -> Fixity -> Constr
489 mkConstr dt str fields fix =
491 { conrep = AlgConstr idx
498 idx = head [ i | (c,i) <- dataTypeConstrs dt `zip` [1..],
499 showConstr c == str ]
502 -- | Gets the constructors
503 dataTypeConstrs :: DataType -> [Constr]
504 dataTypeConstrs dt = case datarep dt of
505 (AlgRep cons) -> cons
506 _ -> error "dataTypeConstrs"
509 -- | Gets the field labels of a constructor
510 constrFields :: Constr -> [String]
511 constrFields = confields
514 -- | Gets the fixity of a constructor
515 constrFixity :: Constr -> Fixity
516 constrFixity = confixity
520 ------------------------------------------------------------------------------
522 -- From strings to constr's and vice versa: all data types
524 ------------------------------------------------------------------------------
527 -- | Gets the string for a constructor
528 showConstr :: Constr -> String
529 showConstr = constring
532 -- | Lookup a constructor via a string
533 readConstr :: DataType -> String -> Maybe Constr
535 case dataTypeRep dt of
536 AlgRep cons -> idx cons
537 IntRep -> mkReadCon (\i -> (mkPrimCon dt str (IntConstr i)))
538 FloatRep -> mkReadCon (\f -> (mkPrimCon dt str (FloatConstr f)))
539 StringRep -> Just (mkStringConstr dt str)
543 -- Read a value and build a constructor
544 mkReadCon :: Read t => (t -> Constr) -> Maybe Constr
545 mkReadCon f = case (reads str) of
546 [(t,"")] -> Just (f t)
549 -- Traverse list of algebraic datatype constructors
550 idx :: [Constr] -> Maybe Constr
551 idx cons = let fit = filter ((==) str . showConstr) cons
557 ------------------------------------------------------------------------------
559 -- Convenience funtions: algebraic data types
561 ------------------------------------------------------------------------------
564 -- | Test for an algebraic type
565 isAlgType :: DataType -> Bool
566 isAlgType dt = case datarep dt of
571 -- | Gets the constructor for an index
572 indexConstr :: DataType -> ConIndex -> Constr
573 indexConstr dt idx = case datarep dt of
574 (AlgRep cs) -> cs !! (idx-1)
575 _ -> error "indexConstr"
578 -- | Gets the index of a constructor
579 constrIndex :: Constr -> ConIndex
580 constrIndex con = case constrRep con of
581 (AlgConstr idx) -> idx
582 _ -> error "constrIndex"
585 -- | Gets the maximum constructor index
586 maxConstrIndex :: DataType -> ConIndex
587 maxConstrIndex dt = case dataTypeRep dt of
588 AlgRep cs -> length cs
589 _ -> error "maxConstrIndex"
593 ------------------------------------------------------------------------------
595 -- Representation of primitive types
597 ------------------------------------------------------------------------------
600 -- | Constructs the Int type
601 mkIntType :: String -> DataType
602 mkIntType = mkPrimType IntRep
605 -- | Constructs the Float type
606 mkFloatType :: String -> DataType
607 mkFloatType = mkPrimType FloatRep
610 -- | Constructs the String type
611 mkStringType :: String -> DataType
612 mkStringType = mkPrimType StringRep
615 -- | Helper for mkIntType, mkFloatType, mkStringType
616 mkPrimType :: DataRep -> String -> DataType
617 mkPrimType dr str = DataType
623 -- Makes a constructor for primitive types
624 mkPrimCon :: DataType -> String -> ConstrRep -> Constr
625 mkPrimCon dt str cr = Constr
629 , confields = error "constrFields"
630 , confixity = error "constrFixity"
634 mkIntConstr :: DataType -> Integer -> Constr
635 mkIntConstr dt i = case datarep dt of
636 IntRep -> mkPrimCon dt (show i) (IntConstr i)
637 _ -> error "mkIntConstr"
640 mkFloatConstr :: DataType -> Double -> Constr
641 mkFloatConstr dt f = case datarep dt of
642 FloatRep -> mkPrimCon dt (show f) (FloatConstr f)
643 _ -> error "mkFloatConstr"
646 mkStringConstr :: DataType -> String -> Constr
647 mkStringConstr dt str = case datarep dt of
648 StringRep -> mkPrimCon dt str (StringConstr str)
649 _ -> error "mkStringConstr"
652 ------------------------------------------------------------------------------
654 -- Non-representations for non-presentable types
656 ------------------------------------------------------------------------------
659 -- | Constructs a non-representation
660 mkNorepType :: String -> DataType
661 mkNorepType str = DataType
667 -- | Test for a non-representable type
668 isNorepType :: DataType -> Bool
669 isNorepType dt = case datarep dt of
675 ------------------------------------------------------------------------------
677 -- Convenience for qualified type constructors
679 ------------------------------------------------------------------------------
682 -- | Gets the unqualified type constructor
683 -- Drop *.*.*... before name
685 tyconUQname :: String -> String
686 tyconUQname x = let x' = dropWhile (not . (==) '.') x
687 in if x' == [] then x else tyconUQname (tail x')
690 -- | Gets the module of a type constructor
691 -- Take *.*.*... before name
692 tyconModule :: String -> String
693 tyconModule x = let (a,b) = break ((==) '.') x
696 else a ++ tyconModule' (tail b)
698 tyconModule' x = let x' = tyconModule x
699 in if x' == "" then "" else ('.':x')