-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMatthias-2015-07-27.txt
367 lines (225 loc) · 9.43 KB
/
Matthias-2015-07-27.txt
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
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
Started in the 30s with Church.
Godel has a language that can prove anything.
Church says you can prove anything with functions.
Set notation was `^ x | x² < 0`, church annotated `'^ | x² < 0`, which was
typeset as `λ | x² < 0`.
e ⩴ x | λx.e | e e
See things as trees:
((λx.x)(λx.x)) = (λ.←) (λ.←)
The names don't matter, the meaning of variable is its binding-site.
λdavid. (david david) = λjeff. (jeff jeff)
"`λ` is just 7th-grade algebra hyped up a little bit."
f(x) ≔ x²
f(6) + 5 = 6² + 5 = 41
(λx.e)e' = e[x←e'] -- β
(λx.x) a = a
(λxy.xyy)ab = (λy.ayy)b = abb
Lambdas are not functions! What about partial functions?
`β` is a relation, and requires a `λ` on the outside.
λx.λy.λz.⸤(λx.x)(zz)⸥y
We can't reduce with `β`.
`β` is a "notion of reduction".
We start defining `=⸤β⸣`:
e β e'
---------
e =⸤β⸥ e'
e =⸤β⸥ e'
---------------
λx.e =⸤β⸥ λx.e'
Template structure is called a "redex".
["redex" is not latin, it just means reducible expression. "contractum" is
latin.]
Need another set of rules..
e =⸤β⸥ e'
----------------
e₀ e =⸤β⸥ e₀ e'
e =⸤β⸥ e'
----------------
e e₀ =⸤β⸥ e' e₀
We are creating a "syntactic compatibility closure".
We also need the reflexive, symmetric and transitive closure of `=⸤β⸥`.
This gives an equivalence relation.
We have "a system of calculating equivalences between terms".
Q: "does something have meaning?"
Two possible meanings:
1. "Can you prove 'true = false', or 'is everything related'"
You need to prove (meta-proof), that you cannot prove (in the system), that
some two terms are equal.
This is called a consistency theorem, developed by Church+Rosser, "the
Church+Rosser lemma".
This shows that the system relates some terms, but not all terms.
2. Is there a topologically, algebraically generated space of functions
generated by `λ` and satisfying `=⸤β⸥`.
This was worked out by Dana Scott.
"lambda-calculus and denotational semantics had a terrible influence on
computer science" --MF
1958: Lisp and Algol 60 were created.
Lisp:
- introduced `λ`-notation, got it wrong
Algol 60:
- based on substitution model of `λ`-calculus
- call-by-name parameter passing (`β`-rule) (was very slow)
- then also introduced call-by-value
- cvn vs cbv "one was correct, one was fast"
For the next 15 years, people struggled to relate call-by-name (correct) with
call-by-value (fast).
Landin (1960s, '62, '63), invented the idea of abstract syntax.
Bohm did the same thing.
McCarthy tried something similar.
Abelson and Sussman make popular "applicative order application".
Dana Scott assigned a mathematical meaning to `λ`-calculus:
1. Created the function space
2. Assigning a mapping from `λ → ⟦⟧`
MF opinion, denotational semantics took us off track.
Plotkin solved all of this (1972/1974) "Call-by-name, call-by-value and the
lambda calculus". Launched enough research ideas to fill 15 people's entire
research lives. Read this paper it's really good!!!
Gives an algorithm to understand what a calculus and a semantics is for a
programming language (13 steps?).
Launched research into CPS.
1. Pick a term language, scoped
2. Pick a subset of terms, called programs, and another subset, called values
(first appearance of words 'program' and 'value' in study of `λ` up to that
point.)
- Programs are things we don't really know what to do with immediately
- Values are things "you see" at the end of computation. `λ` is a value.
.- input
(λi.e) e' ~~~~~~> output
-----
^ program proper
3. Define a notion of reduction: `β` and `β-value`
βᵥ: (λx.e)v ~> e[x←v]
4. Uniformly crate a calculus `=ₓ` from the notions of reduction.
`=ₙ` from β and `=ᵥ` from β and βᵥ
A way to equating arbitrary program fragments.
5. Define a semantics from `=ₓ`
evalₓ ∈ 𝒫(Program × Value)
e evalₓ v 𝑖𝑓𝑓 e =ₓ x
6. Prove that `evalₓ` is a function.
Via Church-Rosser Lemma, `evalˣ` is a (partial) function
evalₓ(e) ≔ { n for "base" value
| 'closure for λ-expression }
You can now prove things like:
e (Y e) =ₙ Y e
Computation should be directed, which for now is not specified, and
problematic.
7. Prove that `=ₓ` satisfies a "standardization" property:
𝑖𝑓 e =ₓ e' 𝑡ℎ𝑒𝑛 then you can do so in an algorithmic fashion
An algorithm means you know how to pick the next redex.
The algorithm is the same for CBN and CBV.
"left-most outer-most strategy", 𝑖.𝑒. standard reduction. `|-->ₓ`.
A strategy is a meta-function for picking a redex.
"If all you care about is the value at the end, you can use standard
reduction".
evalₓ(e) = v 𝑖𝑓𝑓 e |-->ₓ* v
Proof in Curry and Fays, Curry Fays theorem.
(Aside: you must give readers a guide for how to pronounce math notation! A
reader should be able to read your paper aloud.)
We have two semantics, `evalₓ` based on standard reduction, and `=ₓ` based on
equality.
Must prove that `evalₓSR` is the same function as `evalₓ=`.
CBN calculus inconsistent with CBV interpreter, CBV calculus inconsistent with
CBN interpreter.
What do calculations on program mean?
1. (Syntactic) because you prove Church/Rosser, you know that calculations are
consistent with the "fast" interpreter
2. (Semantic) via snippet from Jim Morris (63) dissertation, created
polymorphic lambda calculus (PAL): introduce a relation known as
observational equivalence.
`e ≃ e'` means for all ways of placing a term into a complete program (a
context) called C, evalₓ(C[e]) ~ evalₓ(C[e'])
Two versions: `≃ₙ` and `≃ᵥ`. These are the largest possible consistent
equivalence relations that let you calculate programs. Therefore they are
unique (because they are larges). They are the _truth_.
Every programming language has "the truth" (`≃ₙ`) by virtue of having an
interpreter. The goal is to make the proof system (`=ₓ`) consistent with the
truth.
MF: "On the expressive power of programming languages", previous draft
attempted to prove `≃ᵥ ⊆ ≃ₙ`, was proved different two months earlier.
CBV and CBN functional programming are not related other than in the syntax of
the terms. CBN is not "a different strategy".
Laziness and CBN are related, by subset.
Q: what use is studying functional programming if programs aren't purely
functional?
(f (call/cc g)) ~ g(f)
A calculus equation for a very imperative idea.
Technical insights: "evaluation context semantics" _use contexts instead of
inference rules_.
e β e'
--------- <-- inference rule
e =⸤β⸥ e'
"Syntactic compatibility"
"left-most-outer-most"
Contexts:
e ⩴ x | λx.e | e e
C ⩴ □ | λx.C | C e | e C
one-hole contexts.
`C[e]` "textually" put `e` into hole.
(λx.□)(λy.y)
/ \
λ λ←←
| | ↑
□ ⋅→→
with contexts:
=⸤β⸥ : e =⸤β⸥ e' 𝑖𝑓𝑓 ∃ C,
e = C[(λx.e₀)e₁]
e' = C[e₀[x ←e₁]]
Evaluation context:
E ⩴ □ | E e
Thm: E[(λx.e)e'] is the LMOM redex.
For CBV you need:
E ⩴ □ | v E | E e
You could also use:
E ⩴ □ | e E | E v
also left-most-outer-most!
E[(λx.e)e'] |-->ₙ E[e[x←e']]
fully describes CBN standard reduction.
E[(λx.e)v] |-->ᵥ E[e[x←v]]
fully describes CBV standard reduction.
"evaluation context semantics" should be called "standard reduction semantics".
Technical Insight 2:
E[ THING v ]
`THING` can manipulate `E`, the evaluation context.
From this you can do side-effects, continuations, etc.
𝑒.𝑔.
E[raise e] ~> raise e
full equational system for exceptions:
x | λx.e | ee | raise e
calculation system:
C[(λx.e)v] =ₑₓ C[e[x←v]]
C[E[raise e]] =ₑₓ C[raise e]
These two rules give you a consistent Church/Rosser system for exceptions. Same
two equations work for CBN.
Standard reduction:
E[(λx.e)v] |-->ₑₓ E[e[x←v]]
E[E'[raise e]] |-->ₑₓ E[raise e] [ |-->ₑₓ raise e , as a coincidence ]
Standard reduction for assignment:
e = x | λx.e | e e | set! x e | letrec ((x v) ..) e
v = λx.e
E = □ | E e | v E | set! x E
(βₛₑₜ): (λx.e) v R letrec ((x v)) e
(x): letrec (.. (x v) ..) E[x] R letrec (.. (x v) ..) E[v]
(set!): letrec (.. (x v) ..) E[set! x u] R letrec (.. (x u) ..) E[λx.x]
(scope extrusion:)
E[letrec (...) e] R letrec (...) E[e]
(merge:)
letrec (.. (x v) ..) (letrec (.. (y u) ..) e) R letrec (.. (x v) .. .. (y u) ..) e
You can calculate in parallel, but standard reduction doesn't capture parallel
execution.
Technical Insight 3:
t: E[(λx.e)e'] = Pₜ
t+1: E[e[x←e']] = Pₜ₊₁
Idea: separate `E` from the expression where the "machine" is looking for a
redex.
Two register machine: control and stack registers:
⟨e,E⟩
Next idea: change data representation from context to stack:
⟨e,[app₁]⟩
[app₂]
[app₃]
...
Next idea: substitution is hard and inefficient. Make substitution lazy;
reveals an explicit environment.
control: e
environment: ρ mapping free-variables to values
stack: κ control stack