summaryrefslogtreecommitdiff
path: root/ghc/docs/comm/exts/th.html
blob: dbb168aa0e8d5e67649399f5fcaac724e56c6b49 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
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 &lt;module&gt;:&lt;name&gt;.
      <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>