towards monads: tweak error message
[lambda.git] / damn.mdwn
1 1.      Sentences have truth conditions.
2
3 2.      If "John read the book" is true, then it follows that:
4         John read something,  
5         Someone read the book,  
6         John did something to the book,  
7         etc.
8
9 3. If "John read the damn book",
10    all the same entailments follow.
11    To a first approximation, "damn" does not affect at-issue truth
12    conditions.  
13
14 4. "Damn" does contribute information about the attitude of the speaker
15    towards some aspect of the situation described by the sentence.
16
17
18 Expressives such as "damn" have side effects that don't affect the
19 at-issue value of the sentence in which they occur.  What this claim
20 says is unpacked at some length here: <http://tinyurl.com/cbarker/salt/interaction/salt.pdf>.
21
22 In brief, "The man read the damn book" means the same thing as "The
23 man read the book" as far as what must be the case in the world for
24 the sentence to be true.  However, the sentence with the "damn" in it
25 in addition conveys the claim that something about the described
26 situtation is not as it should be.  (The person who is committed to
27 that claim is whoever utters the sentence.)
28
29 So we need a way of evaluating sentences that allows "damn" to launch
30 a side effect without affecting the truth conditions of the sentence
31 in which it occurs.
32
33 Furthermore, we don't want to change the meaning of "the", "man",
34 "read", or "book"---those elements are completely innocent, and
35 shouldn't be burdened with helping compute affective content.
36
37
38
39 What we did in Monday's seminar
40 ===============================
41
42 We start with a simulation of semantic composition:
43
44         (cons (cons 'the 'man) 
45                   (cons 'read
46                                 (cons 'the
47                                           'book)))
48
49 That evaluates to nested structure of pairs, that Scheme displays as:
50
51         '((the . man) . (read . (the . book)))
52
53 If you try it yourself, you may see instead:
54
55         '((the . man) read the . book)
56
57 This is shorthand for the same thing. Just trust me on that.
58
59 What's going on here?
60 ---------------------
61
62 `(cons M N)` is a request to build an ordered pair out of the values M and N.
63 Scheme displays that pair as `'(M . N)` You can't write `(M . N)` yourself and expect Scheme to understand that you're talking about this pair. If you tried to, Scheme would think you're trying to apply the function M to some arguments, which you're not, and also
64 Scheme would be confused by what argument the `.` is supposed to be. So, you say:
65
66         (cons M N)
67
68 and that evaluates to an ordered pair, and Scheme displays that ordered pair as
69
70         '(M . N)
71
72 You *can* write `'(M . N)` (with the prefixed single quote), and Scheme will understand you then. However, we're going to be using that same single quote prefix to do something else in a moment, and I don't want now to explain how these uses are related. So we'll write out `(cons M N)` longhand, and we'll leave the `'(M . N)` notation to Scheme for displaying the pair we built.
73
74 There is an underlying reason why parentheses are used both when displaying the ordered pair, and also to mean "apply this function to these arguments." However, at this point, you may well see this as a confusing overloading of parentheses to fill different syntactic roles.
75
76 Now what about the elements of our ordered pairs. Why do we say `(cons 'the 'man)`. Why are those single quotes there? Well, if you just said `(cons the man)`, Scheme would understand `the` and `man` to be variables, and it would complain that you hadn't bound these variables to any values. We don't want to build an ordered pair out of the values possessed by variables `the` and `man`. Instead, we want to just make up some primitive value THE to stand for the meaning of an object-language determiner, and some primitive value MAN to stand for the meaning of an object-language noun. The notation `'the` is Scheme's way of designating a primitive atomic value. Note there is no closing single quote, only a prefixed one. Scheme calls these primitive atomic values "symbols." That term is a bit misleading, because the symbol `'the` is not the same as the variable `the`. Neither is it the same as what's called the string `"the"`. The latter is a structured value, composed out of three character values. The symbol `'the`, on the other hand, is an atomic value. It has no parts. (The notation the programmer uses to designate this atomic value has four characters, but the value designated itself has no parts.) If you think this is all somewhat confusing, you're right. It gets easier with practice.
77
78 `'the` can also be written `(quote the)`. This is even more confusing, because here the `the` is not interpreted as a variable. (Try `(let* ((the 3)) (quote the))`.) If you come across `(quote the)`, just read it as a verbose (and perhaps misleading) way of writing `'the`, not as the application of any function to any value.
79
80 Okay, so what we've done is just create a bunch of new atomic values `'the`, `'man`, and so on. Scheme doesn't know how to do much with these. It knows for instance that `'the` is the same value as `'the` and a different value than `'man`. But it doesn't know much more than that. That's all we need or want here.
81
82 And we built a tree out of those values, representing the tree by a nested structure of pairs of leaf-labels.
83
84 The program we submitted to Scheme:
85
86         (cons (cons 'the 'man) 
87                   (cons 'read
88                                 (cons 'the
89                                           'book)))
90
91 evaluates to the nested structure of pairs that Scheme displays as:
92
93         '((the . man) . (read . (the . book)))
94
95 ---or as an equivalent shorthand. And although there aren't `'`s prefixed to each of the elements of this nested structure, those elements are still the `'the`, `'man` and so on primitive atomic values that we specified. Not the values (if any) possessed by some variables `the`, `man`, and so on.
96
97 We can think of this nested structure of pairs as the tree:
98
99                                  /----------------\
100                                 /                  \
101                            /                    \
102                           /                      \
103                          /                        \                                  
104                         / \                      / \
105                    /   \                    /   \
106                   /     \                  /     \
107                  /       \                /       \
108         meaning of   meaning of   meaning of   \
109           "the"        "man"       "read"      / \
110                                                                                   /   \
111                                                                                  /     \
112                                                                                 /       \
113                                                                         meaning of  meaning of
114                                                                           "the"      "book"
115
116 Okay, let's get back to "damn."
117
118 We start by defining `damn` as a "thunk" that when applied to zero arguments returns a trivial adjectival meaning, which we'll designate with the primitive symbol `'id`.
119
120 What's a "thunk"?
121 -----------------
122
123 Remember, in Scheme you can have functions that take one value, and also functions that take two values, and also functions that take zero values. The last ones are called "thunks." The thunk is not identical to the value it returns. For instance:
124
125         (lambda () 3)
126
127 is a thunk that returns the integer 3. If we bind the variable `t` to that thunk, then `t` is a function (Scheme will display it as `#<procedure>`)
128 not an integer. Whereas `(t)` is an integer not a function.
129
130 There's no reason yet on hand for us to make `damn` be a thunk. For present purposes, we could also just define `damn` to be the symbol `'id`. But what we're going to go on to do does require us to make `damn` be a thunk. The reason for that is to postpone the evaluation of some expressions until the continuations we want to operate on are in place. So for uniformity we're going to make `damn` be a thunk right from the beginning.
131
132 As we said, `damn` starts as a thunk that returns a trivial adjectival meaning `'id`:
133
134         (define damn (lambda () 'id))
135
136 Now we can say:
137
138         (cons (cons 'the 'man) 
139                   (cons 'read
140                                 (cons 'the
141                                           (cons (damn) 
142                                                 'book))))
143
144 and we get back:
145
146         '((the . man) . (read . (the . (id . book))))
147
148 ---or an equivalent shorthand. (I'm now going to stop saying this.)
149
150
151 How to get some affective meaning into damn?
152 --------------------------------------------
153
154 We might try:
155
156
157         (define damn (lambda () 'bad))
158
159 But then:
160
161         (cons (cons 'the 'man) 
162                   (cons 'read
163                                 (cons 'the
164                                           (cons (damn) 
165                                                 'book))))
166
167 gives us:
168
169         '((the . man) . (read . (the . (bad . book))))
170
171 Which is not quite what we're looking for. We don't want to contribute the normal adjectival meaning of "bad" to the proposition asserted. Instead we want badness to be a side-issue linguistic contribution. We might try:
172
173         (define damn (lambda () (cons 'side-effect 'bad)))
174
175 But then we'd get:
176
177         '((the . man) . (read . (the . ((side-effect . bad) . book))))
178
179 and we said at the outset that the context `(the . (<> . book))` shouldn't need to know how to interact with affective meanings. (I'll use `<>` to indicate a "hole" in a larger expression.)
180
181
182 Let's use continuations
183 -----------------------
184
185 A promising way to handle this is with **continuations**, which you will get much more familiar with as this seminar progresses. Don't worry about not understanding what's going on quite yet. This is just an advertisement that's supposed to provoke your imagination.
186
187 Chris and others have applied the apparatus of continuations to the analysis of expressives in the paper cited at the top. For a simple in-class demonstration, here's what we tried to do.
188
189         (call/cc (lambda (k) ...))
190
191 is Scheme's way of saying:
192         
193 >       bind the continuation of this complex expression to `k` and evaluate the `...`
194
195
196 So now we define `damn` like this:
197
198         (define damn (lambda () (call/cc (lambda (k) (print "bad") (k 'id)))))
199
200 In other words, `damn` is a thunk. When that thunk is applied---we evaluate `(damn)`---we capture the pending future of that application and bind that to `k`. Then we print "bad" and supply the argument `'id` to `k`. This last step means we go on evaluating the pending future as if `(damn)` had simply returned `'id`.
201
202 What happens then when we evaluate:
203
204         (cons (cons 'the 'man) 
205                   (cons 'read
206                                 (cons 'the
207                                           (cons (damn) 
208                                                 'book))))
209
210 We get something like this:
211
212 <blockquote>
213 <strong>"bad"</strong> '((the . man) . (read . (the . (id . book))))
214 </blockquote>
215
216 Yay! The affective meaning has jumped out of the compositional evaluation of the main sentence, and the context `(the . (<> . book))` only has to deal with the trivial adjectival meaning `'id`.
217
218
219 But...
220 ------
221
222 As came out in discussion, the `print` we're using here already constitutes a kind of side-effect mechanism of its own. If you say:
223
224         (define three-thunk (lambda () (print "hi") 3))
225
226 and then ask for the evaluation of:
227
228         (+ (+ 2 (three-thunk)) 1)
229
230 you'll see something like:
231
232 <blockquote>
233 <strong>"hi"</strong> 6
234 </blockquote>
235
236 In other words, the printing of "hi" already happens on the side, outside of the main evaluation. Continuations don't need to be explicitly invoked.
237
238 So the demonstration we tried in class was pedagogically flawed. It didn't properly display how continuations are a minimally effective apparatus for representing affective meaning. In fact, continuations *were* still doing the work, but it wasn't the explicit continuations we were writing out for you. It was instead continuations implicit in the `print` operation.
239
240 So a better demonstration would do without any device like `print` that already incorporates continuations implicitly. Any continuation-manipulation should be fully explicit.
241
242
243 Can we do better?
244 -----------------
245
246 Instead of representing the side-issue affective contribution by printing "bad", let's instead try to build a pair of side-effect contributions and at-issue assertion. Then what we want would be something like:
247
248         '((side-effect . bad) . ((the . man) . (read . (the . (id . book)))))
249
250 Only we want to get this from the evaluation of:
251
252         (cons (cons 'the 'man) 
253                   (cons 'read
254                                 (cons 'the
255                                           (cons (damn) 
256                                                 'book))))
257
258 where `(damn)` doesn't have widest scope. And we don't want to have to recruit all the other semantic material into accepting and passing along a possible affective argument.
259
260 How to do this?
261
262 It's not immediately clear how to do it with "undelimited" continuations, of the sort captured by `call/cc`. This is the natural first thing to try:
263
264
265         (define damn (lambda () (call/cc (lambda (k) (cons (cons 'side-effect 'bad) (k 'id))))))
266
267
268 The idea here is we capture the continuation that `(damn)` has when it gets evaluated. This continuation is bound to the variable `k`. We supply `'id` as an argument to that continuation. When the main, at-issue tree is all built, then we return a pair `'((side-effect . bad) . AT-ISSUE-TREE)`.
269
270 However, this doesn't work. The reason is that an undelimited continuation represents the future of the evaluation of `(damn)` *until the end of the computation*. So when `'id` is supplied to `k`, we go back to building the at-issue tree until we're finished *and that's the end of the computation*. We never get to go back and evaluate the application of `(cons (cons 'side-effect 'bad) <>)` to anything.
271
272
273 With delimited continuations
274 ------------------------------
275
276 The straightforward way to fix this is to use, not undelimited continuations, but instead a more powerful apparatus called "delimited continuations." These too will be explained in due course, don't expect to understand all this now.
277
278 A delimited continuation is captured not by using `call/cc`, but instead by using a variety of other operators. We'll use the operator `shift`. This substitutes for `call/cc`. The syntax in Scheme is slightly different. Whereas we wrote:
279
280         (call/cc (lambda (k) ...))
281
282 we instead write:
283
284         (shift k ...)
285
286 but the behavior is the same. It's just that now our continuation doesn't stretch until the end of the computation, but only up to some specified limit. The limit of the continuation is specified using the syntax:
287
288         (reset ...)
289
290 This is a kind of continuation-scope-marker. There are some interesting default behaviors if you don't explicitly specify where the limits are. In fact, in the interactive interpreter we wouldn't need to ever explicitly mark the scopes. They'd by default be just where we want them to be. But we'll be fully explicit here.
291
292 If a block `...` never invokes a shift, then `(reset ...)` will evaluate just the same as `...`. So for uniformity, we can designate our continuation-scopes even on computations that don't capture and manipulate continuations.
293
294 Going back to the beginning, then. We start with:
295
296         (require racket/control) ; this tells Scheme to let us use shift and reset
297
298         (define damn (lambda () 'id))
299
300 We evaluate:
301
302         (reset (cons (cons 'the 'man) 
303                   (cons 'read
304                                 (cons 'the
305                                           (cons (damn) 
306                                                 'book)))))
307
308 Remember, the reset isn't actually *doing* anything. It's not a function that's taking the other material as an argument. It's instead a scope-marker. Here it's not even needed; but we're inserting it anyway to be explicit and uniform.
309
310 Evaluating that gives us:
311
312         '((the . man) . (read . (the . (id . book))))
313
314
315 Now to pair that with an affective side-issue content, we'd instead define `damn` as:
316
317         (define damn (lambda () (shift k (cons (cons 'side-effect 'bad) (k 'id)))))
318
319 And voil&agrave;!
320
321         (reset (cons (cons 'the 'man) 
322                   (cons 'read
323                                 (cons 'the
324                                           (cons (damn) 
325                                                         'book)))))
326
327 evaluates to:
328
329         '((side-effect . bad) ((the . man) . (read . (the . (id . book)))))
330
331 So that's the straightforward way of repairing the strategy we used in class, without using `print`. We also have to switch to using delimited continuations.
332
333
334 Ken's proposal
335 --------------
336
337 Ken Shan pointed out a lovely way to get to the same end-point still using only undelimited continuations (`call/cc`).
338
339         (let ((pragma
340                    ; An ordered pair whose first component is the assertion
341                    ; operator, a unary function, and whose second component
342                    ; is the meaning of "damn", a thunk.
343                    (call/cc (lambda (k)
344                           (cons (lambda (p) p)
345                                         (lambda () (k (cons (lambda (p) (cons (cons 'side-effect 'bad) p))
346                                                                                 (lambda () 'id)))))))))
347           (let ((assert (car pragma)) ; this binds assert to the first element of the pair pragma
348                         (damn   (cdr pragma))) ; this binds damn to the second element of the pair pragma
349                 (assert (cons (cons 'the 'man) (cons 'read (cons 'the (cons (damn) 'book)))))))
350
351 We won't do much to explain this. We'll just leave it for you to digest, perhaps later in the course. When you succeed in doing so, you will be as delighted by it as we are.
352