X-Git-Url: http://git.megacz.com/?p=ghc-hetmet.git;a=blobdiff_plain;f=docs%2Fcomm%2Fexts%2Fth.html;fp=docs%2Fcomm%2Fexts%2Fth.html;h=dbb168aa0e8d5e67649399f5fcaac724e56c6b49;hp=0000000000000000000000000000000000000000;hb=0065d5ab628975892cea1ec7303f968c3338cbe1;hpb=28a464a75e14cece5db40f2765a29348273ff2d2 diff --git a/docs/comm/exts/th.html b/docs/comm/exts/th.html new file mode 100644 index 0000000..dbb168a --- /dev/null +++ b/docs/comm/exts/th.html @@ -0,0 +1,197 @@ + + + + + The GHC Commentary - Template Haskell + + + +

The GHC Commentary - Template Haskell

+

+ The Template Haskell (TH) extension to GHC adds a meta-programming + facility in which all meta-level code is executed at compile time. The + design of this extension is detailed in "Template Meta-programming for + Haskell", Tim Sheard and Simon Peyton Jones, ACM + SIGPLAN 2002 Haskell Workshop, 2002. However, some of the details + changed after the paper was published. +

+ +

Meta Sugar

+

+ The extra syntax of TH (quasi-quote brackets, splices, and reification) + is handled in the module DsMeta. + In particular, the function dsBracket desugars the four + types of quasi-quote brackets ([|...|], + [p|...|], [d|...|], and [t|...|]) + and dsReify desugars the three types of reification + operations (reifyType, reifyDecl, and + reifyFixity). +

+ +

Desugaring of Quasi-Quote Brackets

+

+ A term in quasi-quote brackets needs to be translated into Core code + that, when executed, yields a representation of that term in + the form of the abstract syntax trees defined in Language.Haskell.TH.Syntax. + Within DsMeta, this is achieved by four functions + corresponding to the four types of quasi-quote brackets: + repE (for [|...|]), repP (for + [p|...|]), repTy (for [t|...|]), + and repTopDs (for [d|...|]). All four of + these functions receive as an argument the GHC-internal Haskell AST of + the syntactic form that they quote (i.e., arguments of type HsExpr.HsExpr + Name, HsPat.HsPat Name, + HsType.HsType + Name, and HsDecls.HsGroup + Name, respectively). +

+

+ To increase the static type safety in DsMeta, the functions + constructing representations do not just return plain values of type CoreSyn + .CoreExpr; instead, DsMeta introduces a + parametrised type Core whose dummy type parameter indicates + the source-level type of the value computed by the corresponding Core + expression. All construction of Core fragments in DsMeta + is performed by smart constructors whose type signatures use the dummy + type parameter to constrain the contexts in which they are applicable. + For example, a function that builds a Core expression that evaluates to + a TH type representation, which has type + Language.Haskell.TH.Syntax.Type, would return a value of + type +

+
+
+Core Language.Haskell.TH.Syntax.Type
+
+ +

Desugaring of Reification Operators

+

+ The TH paper introduces four reification operators: + reifyType, reifyDecl, + reifyFixity, and reifyLocn. Of these, + currently (= 9 Nov 2002), only the former two are implemented. +

+

+ The operator reifyType receives the name of a function or + data constructor as its argument and yields a representation of this + entity's type in the form of a value of type + TH.Syntax.Type. Similarly, reifyDecl receives + the name of a type and yields a representation of the type's declaration + as a value of type TH.Syntax.Decl. The name of the reified + entity is mapped to the GHC-internal representation of the entity by + using the function lookupOcc on the name. +

+ +

Representing Binding Forms

+

+ Care needs to be taken when constructing TH representations of Haskell + terms that include binding forms, such as lambda abstractions or let + bindings. To avoid name clashes, fresh names need to be generated for + all defined identifiers. This is achieved via the routine + DsMeta.mkGenSym, which, given a Name, produces + a Name / Id pair (of type + GenSymBind) that associates the given Name + with a Core identifier that at runtime will be bound to a string that + contains the fresh name. Notice the two-level nature of this + arrangement. It is necessary, as the Core code that constructs the + Haskell term representation may be executed multiple types at runtime + and it must be ensured that different names are generated in each run. +

+

+ Such fresh bindings need to be entered into the meta environment (of + type DsMonad.DsMetaEnv), + which is part of the state (of type DsMonad.DsEnv) + maintained in the desugarer monad (of type DsMonad.DsM). + This is done using the function DsMeta.addBinds, which + extends the current environment by a list of GenSymBinds + and executes a subcomputation in this extended environment. Names can + be looked up in the meta environment by way of the functions + DsMeta.lookupOcc and DsMeta.lookupBinder; more + details about the difference between these two functions can be found in + the next subsection. +

+

+ NB: DsMeta uses mkGenSym only when + representing terms that may be embedded into a context where names can + be shadowed. For example, a lambda abstraction embedded into an + expression can potentially shadow names defined in the context it is + being embedded into. In contrast, this can never be the case for + top-level declarations, such as data type declarations; hence, the type + variables that a parametric data type declaration abstracts over are not + being gensym'ed. As a result, variables in defining positions are + handled differently depending on the syntactic construct in which they + appear. +

+ +

Binders Versus Occurences

+

+ Name lookups in the meta environment of the desugarer use two functions + with slightly different behaviour, namely DsMeta.lookupOcc + and lookupBinder. The module DsMeta contains + the following explanation as to the difference of these functions: +

+
+
+When we desugar [d| data T = MkT |]
+we want to get
+	Data "T" [] [Con "MkT" []] []
+and *not*
+	Data "Foo:T" [] [Con "Foo:MkT" []] []
+That is, the new data decl should fit into whatever new module it is
+asked to fit in.   We do *not* clone, though; no need for this:
+	Data "T79" ....
+
+But if we see this:
+	data T = MkT 
+	foo = reifyDecl T
+
+then we must desugar to
+	foo = Data "Foo:T" [] [Con "Foo:MkT" []] []
+
+So in repTopDs we bring the binders into scope with mkGenSyms and addBinds,
+but in dsReify we do not.  And we use lookupOcc, rather than lookupBinder
+in repTyClD and repC.
+
+

+ This implies that lookupOcc, when it does not find the name + in the meta environment, uses the function DsMeta.globalVar + to construct the original name of the entity (cf. the TH paper + for more details regarding original names). This name uniquely + identifies the entity in the whole program and is in scope + independent of whether the user name of the same entity is in + scope or not (i.e., it may be defined in a different module without + being explicitly imported) and has the form <module>:<name>. + NB: Incidentally, the current implementation of this + mechanisms facilitates breaking any abstraction barrier. +

+ +

Known-key Names for Template Haskell

+

+ During the construction of representations, the desugarer needs to use a + large number of functions defined in the library + Language.Haskell.TH.Syntax. The names of these functions + need to be made available to the compiler in the way outlined Primitives and the Prelude. + Unfortunately, any change to PrelNames + triggers a significant amount of recompilation. Hence, the names needed + for TH are defined in DsMeta instead (at the end of the + module). All library functions needed by TH are contained in the name + set DsMeta.templateHaskellNames. +

+ +

+ +Last modified: Wed Nov 13 18:01:48 EST 2002 + + + +