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 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. +
+ +
+ 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
).
+
+ 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+
+ 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.
+
+ 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 GenSymBind
s
+ 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.
+
+ 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.
+
+ 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 + + + +