-be instantiated in several ways to map over the immediate subterms of
-a term; see the "gmap" combinators later in this module. Indeed, a
-generic programmer does not necessarily need to use the ingenious
-gfoldl primitive but rather the intuitive "gmap" combinators. The
-"gfoldl" primitive is completed by means to query top-level
-constructors, to turn constructor representations into proper terms,
-and to list all possible datatype constructors. This completion
-allows us to serve generic programming scenarios like read, show,
-equality, term generation.
+be instantiated in several ways to map over the immediate subterms
+of a term; see the @gmap@ combinators later in this class. Indeed, a
+generic programmer does not necessarily need to use the ingenious gfoldl
+primitive but rather the intuitive @gmap@ combinators. The 'gfoldl'
+primitive is completed by means to query top-level constructors, to
+turn constructor representations into proper terms, and to list all
+possible datatype constructors. This completion allows us to serve
+generic programming scenarios like read, show, equality, term generation.
+
+The combinators 'gmapT', 'gmapQ', 'gmapM', etc are all provided with
+default definitions in terms of 'gfoldl', leaving open the opportunity
+to provide datatype-specific definitions.
+(The inclusion of the @gmap@ combinators as members of class 'Data'
+allows the programmer or the compiler to derive specialised, and maybe
+more efficient code per datatype. /Note/: 'gfoldl' is more higher-order
+than the @gmap@ combinators. This is subject to ongoing benchmarking
+experiments. It might turn out that the @gmap@ combinators will be
+moved out of the class 'Data'.)
+
+Conceptually, the definition of the @gmap@ combinators in terms of the
+primitive 'gfoldl' requires the identification of the 'gfoldl' function
+arguments. Technically, we also need to identify the type constructor
+@c@ for the construction of the result type from the folded term type.
+
+In the definition of @gmapQ@/x/ combinators, we use phantom type
+constructors for the @c@ in the type of 'gfoldl' because the result type
+of a query does not involve the (polymorphic) type of the term argument.
+In the definition of 'gmapQl' we simply use the plain constant type
+constructor because 'gfoldl' is left-associative anyway and so it is
+readily suited to fold a left-associative binary operation over the
+immediate subterms. In the definition of gmapQr, extra effort is
+needed. We use a higher-order accumulation trick to mediate between
+left-associative constructor application vs. right-associative binary
+operation (e.g., @(:)@). When the query is meant to compute a value
+of type @r@, then the result type withing generic folding is @r -> r@.
+So the result of folding is a function to which we finally pass the
+right unit.
+
+With the @-fglasgow-exts@ option, GHC can generate instances of the
+'Data' class automatically. For example, given the declaration
+
+> data T a b = C1 a b | C2 deriving (Typeable, Data)
+
+GHC will generate an instance that is equivalent to
+
+> instance (Data a, Data b) => Data (T a b) where
+> gfoldl k z (C1 a b) = z C1 `k` a `k` b
+> gfoldl k z C2 = z C2
+>
+> gunfold k z c = case constrIndex c of
+> 1 -> k (k (z C1))
+> 2 -> z C2
+>
+> toConstr (C1 _ _) = con_C1
+> toConstr C2 = con_C2
+>
+> dataTypeOf _ = ty_T
+>
+> con_C1 = mkConstr ty_T "C1" [] Prefix
+> con_C2 = mkConstr ty_T "C2" [] Prefix
+> ty_T = mkDataType "Module.T" [con_C1, con_C2]
+
+This is suitable for datatypes that are exported transparently.