diff options
Diffstat (limited to 'docs/comm/exts/th.html')
-rw-r--r-- | docs/comm/exts/th.html | 197 |
1 files changed, 197 insertions, 0 deletions
diff --git a/docs/comm/exts/th.html b/docs/comm/exts/th.html new file mode 100644 index 0000000000..dbb168aa0e --- /dev/null +++ b/docs/comm/exts/th.html @@ -0,0 +1,197 @@ +<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> +<html> + <head> + <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=ISO-8859-1"> + <title>The GHC Commentary - Template Haskell</title> + </head> + + <body BGCOLOR="FFFFFF"> + <h1>The GHC Commentary - Template Haskell</h1> + <p> + 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, <a + href="http://portal.acm.org/toc.cfm?id=581690&type=proceeding&coll=portal&dl=ACM&part=series&WantType=proceedings&idx=unknown&title=unknown">ACM + SIGPLAN 2002 Haskell Workshop,</a> 2002. However, some of the details + changed after the paper was published. + </p> + + <h2>Meta Sugar</h2> + <p> + The extra syntax of TH (quasi-quote brackets, splices, and reification) + is handled in the module <a + href="http://cvs.haskell.org/cgi-bin/cvsweb.cgi/fptools/ghc/compiler/deSugar/DsMeta.hs"><code>DsMeta</code></a>. + In particular, the function <code>dsBracket</code> desugars the four + types of quasi-quote brackets (<code>[|...|]</code>, + <code>[p|...|]</code>, <code>[d|...|]</code>, and <code>[t|...|]</code>) + and <code>dsReify</code> desugars the three types of reification + operations (<code>reifyType</code>, <code>reifyDecl</code>, and + <code>reifyFixity</code>). + </p> + + <h3>Desugaring of Quasi-Quote Brackets</h3> + <p> + A term in quasi-quote brackets needs to be translated into Core code + that, when executed, yields a <em>representation</em> of that term in + the form of the abstract syntax trees defined in <a + href="http://cvs.haskell.org/cgi-bin/cvsweb.cgi/fptools/libraries/template-haskell/Language/Haskell/TH/Syntax.hs"><code>Language.Haskell.TH.Syntax</code></a>. + Within <code>DsMeta</code>, this is achieved by four functions + corresponding to the four types of quasi-quote brackets: + <code>repE</code> (for <code>[|...|]</code>), <code>repP</code> (for + <code>[p|...|]</code>), <code>repTy</code> (for <code>[t|...|]</code>), + and <code>repTopDs</code> (for <code>[d|...|]</code>). 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 <a + href="http://cvs.haskell.org/cgi-bin/cvsweb.cgi/fptools/ghc/compiler/hsSyn/HsExpr.lhs"><code>HsExpr</code></a><code>.HsExpr + Name</code>, <a href="http://cvs.haskell.org/cgi-bin/cvsweb.cgi/fptools/ghc/compiler/hsSyn/HsPat.lhs"><code>HsPat</code></a><code>.HsPat Name</code>, + <a + href="http://cvs.haskell.org/cgi-bin/cvsweb.cgi/fptools/ghc/compiler/hsSyn/HsTypes.lhs"><code>HsType</code></a><code>.HsType + Name</code>, and <a + href="http://cvs.haskell.org/cgi-bin/cvsweb.cgi/fptools/ghc/compiler/hsSyn/HsDecls.lhs"><code>HsDecls</code></a><code>.HsGroup + Name</code>, respectively). + </p> + <p> + To increase the static type safety in <code>DsMeta</code>, the functions + constructing representations do not just return plain values of type <a + href="http://cvs.haskell.org/cgi-bin/cvsweb.cgi/fptools/ghc/compiler/coreSyn/CoreSyn.lhs"><code>CoreSyn</code></a> + <code>.CoreExpr</code>; instead, <code>DsMeta</code> introduces a + parametrised type <code>Core</code> whose dummy type parameter indicates + the source-level type of the value computed by the corresponding Core + expression. All construction of Core fragments in <code>DsMeta</code> + 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 + <code>Language.Haskell.TH.Syntax.Type</code>, would return a value of + type + </p> + <blockquote> + <pre> +Core Language.Haskell.TH.Syntax.Type</pre> + </blockquote> + + <h3>Desugaring of Reification Operators</h3> + <p> + The TH paper introduces four reification operators: + <code>reifyType</code>, <code>reifyDecl</code>, + <code>reifyFixity</code>, and <code>reifyLocn</code>. Of these, + currently (= 9 Nov 2002), only the former two are implemented. + </p> + <p> + The operator <code>reifyType</code> 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 + <code>TH.Syntax.Type</code>. Similarly, <code>reifyDecl</code> receives + the name of a type and yields a representation of the type's declaration + as a value of type <code>TH.Syntax.Decl</code>. The name of the reified + entity is mapped to the GHC-internal representation of the entity by + using the function <code>lookupOcc</code> on the name. + </p> + + <h3>Representing Binding Forms</h3> + <p> + 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 + <code>DsMeta.mkGenSym</code>, which, given a <code>Name</code>, produces + a <code>Name</code> / <code>Id</code> pair (of type + <code>GenSymBind</code>) that associates the given <code>Name</code> + 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. + </p> + <p> + Such fresh bindings need to be entered into the meta environment (of + type <a + href="http://cvs.haskell.org/cgi-bin/cvsweb.cgi/fptools/ghc/compiler/deSugar/DsMonad.lhs"><code>DsMonad</code></a><code>.DsMetaEnv</code>), + which is part of the state (of type <code>DsMonad.DsEnv</code>) + maintained in the desugarer monad (of type <code>DsMonad.DsM</code>). + This is done using the function <code>DsMeta.addBinds</code>, which + extends the current environment by a list of <code>GenSymBind</code>s + and executes a subcomputation in this extended environment. Names can + be looked up in the meta environment by way of the functions + <code>DsMeta.lookupOcc</code> and <code>DsMeta.lookupBinder</code>; more + details about the difference between these two functions can be found in + the next subsection. + </p> + <p> + NB: <code>DsMeta</code> uses <code>mkGenSym</code> 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. + </p> + + <h3>Binders Versus Occurences</h3> + <p> + Name lookups in the meta environment of the desugarer use two functions + with slightly different behaviour, namely <code>DsMeta.lookupOcc</code> + and <code>lookupBinder</code>. The module <code>DsMeta</code> contains + the following explanation as to the difference of these functions: + </p> + <blockquote> + <pre> +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.</pre> + </blockquote> + <p> + This implies that <code>lookupOcc</code>, when it does not find the name + in the meta environment, uses the function <code>DsMeta.globalVar</code> + to construct the <em>original name</em> 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 + <em>independent</em> 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>. + <strong>NB:</strong> Incidentally, the current implementation of this + mechanisms facilitates breaking any abstraction barrier. + </p> + + <h3>Known-key Names for Template Haskell</h3> + <p> + During the construction of representations, the desugarer needs to use a + large number of functions defined in the library + <code>Language.Haskell.TH.Syntax</code>. The names of these functions + need to be made available to the compiler in the way outlined <a + href="../the-beast/prelude.html">Primitives and the Prelude.</a> + Unfortunately, any change to <a + href="http://cvs.haskell.org/cgi-bin/cvsweb.cgi/fptools/ghc/compiler/prelude/PrelNames.lhs"><code>PrelNames</code></a> + triggers a significant amount of recompilation. Hence, the names needed + for TH are defined in <code>DsMeta</code> instead (at the end of the + module). All library functions needed by TH are contained in the name + set <code>DsMeta.templateHaskellNames</code>. + </p> + + <p><small> +<!-- hhmts start --> +Last modified: Wed Nov 13 18:01:48 EST 2002 +<!-- hhmts end --> + </small> + </body> +</html> |