week9 tweak
[lambda.git] / week9.mdwn
index 79ebf40..dac311c 100644 (file)
@@ -100,7 +100,13 @@ Scheme is similar. There are various sorts of reference cells available in Schem
                (set-box! ycell 3)
                (+ x (unbox ycell)))
 
-(C has explicit-style mutable variables, too, which it calls *pointers*. But simple variables in C are already mutable, in the implicit style.)
+C has explicit-style mutable variables, too, which it calls *pointers*. But simple variables in C are already mutable, in the implicit style. Scheme also has both styles of mutation. In addition to the explicit boxes, Scheme also lets you mutate unboxed variables:
+
+       (begin
+               (define x 1)
+               (set! x 2)
+               x)
+       ; evaluates to 2
 
 When dealing with explicit-style mutation, there's a difference between the types and values of `ycell` and `!ycell` (or in Scheme, `(unbox ycell)`). The former has the type `int ref`: the variable `ycell` is assigned a reference cell that contains an `int`. The latter has the type `int`, and has whatever value is now stored in the relevant reference cell. In an implicit-style framework though, we only have the resources to refer to the contents of the relevant reference cell. `y` in fragment [G] or the C snippet above has the type `int`, and only ever evaluates to `int` values.
 
@@ -320,7 +326,7 @@ Similarly:
 Let's consider how to interpet our new syntactic forms `newref`, `deref`, and `setref`:
 
 
-1.     \[[newref starting_val]] should allocate a new reference cell in the store and insert `starting_val` into that cell. It should return some "key" or "index" or "pointer" to the newly created reference cell, so that we can do things like:
+1.     When `expr` evaluates to `starting_val`, **newref expr** should allocate a new reference cell in the store and insert `starting_val` into that cell. It should return some "key" or "index" or "pointer" to the newly created reference cell, so that we can do things like:
 
                let ycell = newref 1
                in ...
@@ -345,7 +351,7 @@ Let's consider how to interpet our new syntactic forms `newref`, `deref`, and `s
                                in (Index new_index, s'')
                        ... 
 
-2.     When `expr` evaluates to a `store_index`, then `deref expr` should evaluate to whatever value is at that index in the current store. (If `expr` evaluates to a value of another type, `deref expr` is undefined.) In this operation, we don't change the store at all; we're just reading from it. So we'll return the same store back unchanged (assuming it wasn't changed during the evaluation of `expr`).
+2.     When `expr` evaluates to a `store_index`, then **deref expr** should evaluate to whatever value is at that index in the current store. (If `expr` evaluates to a value of another type, `deref expr` is undefined.) In this operation, we don't change the store at all; we're just reading from it. So we'll return the same store back unchanged (assuming it wasn't changed during the evaluation of `expr`).
 
                let rec eval expression g s =
                        match expression with
@@ -356,7 +362,7 @@ Let's consider how to interpet our new syntactic forms `newref`, `deref`, and `s
                                in (List.nth s' n, s')
                        ...
 
-3.     When `expr1` evaluates to a `store_index` and `expr2` evaluates to an `int`, then `setref expr1 expr2` should have the effect of changing the store so that the reference cell at that index now contains that `int`. We have to make a decision about what value the `setref ...` call should itself evaluate to; OCaml makes this `()` but other choices are also possible. Here I'll just suppose we've got some appropriate value in the variable `dummy`.
+3.     When `expr1` evaluates to a `store_index` and `expr2` evaluates to an `int`, then **setref expr1 expr2** should have the effect of changing the store so that the reference cell at that index now contains that `int`. We have to make a decision about what value the `setref ...` call should itself evaluate to; OCaml makes this `()` but other choices are also possible. Here I'll just suppose we've got some appropriate value in the variable `dummy`.
 
                let rec eval expression g s =
                        match expression with
@@ -500,62 +506,73 @@ To get the whole process started, the complex computation so defined will need t
 
 -- FIXME --
 
-    [H] ; *** aliasing ***
-        let y be 2 in
-          let x be y in
-            let w alias y in
-              (y, x, w)           ==> (2, 2, 2)
-
-    [I] ; mutation plus aliasing
-        let y be 2 in
-          let x be y in
-            let w alias y in
-              change y to 3 then
-                (y, x, w)         ==> (3, 2, 3)
-
-    [J] let f be (lambda (y) -> BODY) in  ; a
-          ... f (EXPRESSION) ...
-
-        (lambda (y) -> BODY) EXPRESSION
-
-        let y be EXPRESSION in            ; b
-          ... BODY ...
-
-    [K] ; *** passing "by reference" ***
-        let f be (lambda (alias w) ->     ; ?
-          BODY
-        ) in
-          ... f (y) ...
-
-        let w alias y in                  ; d
-          ... BODY ...
-
-    [L] let f be (lambda (alias w) ->
-          change w to 2 then
-            w + 2
-        ) in
-          let y be 1 in
-            let z be f (y) in
-              ; y is now 2, not 1
-              (z, y)              ==> (4, 2)
-
-    [M] ; hyper-evaluativity
-        let h be 1 in
-          let p be 1 in
-            let f be (lambda (alias x, alias y) ->
-              ; contrast here: "let z be x + y + 1"
-              change y to y + 1 then
-                let z be x + y in
-                  change y to y - 1 then
-                    z
-            ) in
-              (f (h, p), f (h, h))
-                                  ==> (3, 4)
-
-    Notice: h, p have same value (1), but f (h, p) and f (h, h) differ
-
+       [H] ; *** aliasing ***
+           let y be 2 in
+             let x be y in
+               let w alias y in
+                 (y, x, w)
+                                                               ; evaluates to (2, 2, 2)
+
+       [I] ; mutation plus aliasing
+           let y be 2 in
+             let x be y in
+               let w alias y in
+                 change y to 3 then
+                   (y, x, w)
+                                                               ; evaluates to (3, 2, 3)
+
+       [J] ; as we already know, these are all equivalent:
+       
+           let f be (lambda (y) -> BODY) in  ; #1
+             ... f (EXPRESSION) ...
+       
+           (lambda (y) -> BODY) EXPRESSION   ; #2
+       
+           let y be EXPRESSION in            ; #3
+             ... BODY ...
 
-Fine and Pryor on "coordinated contents" (see, e.g., [Hyper-Evaluativity](http://www.jimpryor.net/research/papers/Hyper-Evaluativity.txt))
+       [K] ; *** passing by reference ***
+           ; now think: "[J#1] is to [J#3] as [K#1] is to [K#2]"
+       
+           ?                                 ; #1
+       
+           let w alias y in                  ; #2
+             ... BODY ...
+       
+           ; We introduce a special syntactic form to supply
+           ; the missing ?
+       
+           let f be (lambda (alias w) ->     ; #1
+             BODY
+           ) in
+             ... f (y) ...
+
+       [L] let f be (lambda (alias w) ->
+             change w to 2 then
+               w + 2
+           ) in
+             let y be 1 in
+               let z be f (y) in
+                 ; y is now 2, not 1
+                 (z, y)
+                                                               ; evaluates to (4, 2)
+
+       [M] ; hyper-evaluativity
+           let h be 1 in
+             let p be 1 in
+               let f be (lambda (alias x, alias y) ->
+                 ; contrast here: "let z be x + y + 1"
+                 change y to y + 1 then
+                   let z be x + y in
+                     change y to y - 1 then
+                       z
+               ) in
+                 (f (h, p), f (h, h))
+                                                               ; evaluates to (3, 4)
+
+Notice: in [M], `h` and `p` have same value (1), but `f (h, p)` and `f (h, h)` differ.
+
+See Pryor's "[Hyper-Evaluativity](http://www.jimpryor.net/research/papers/Hyper-Evaluativity.txt)".
 
 
 ##Four grades of mutation involvement##
@@ -567,7 +584,7 @@ Programming languages tend to provide a bunch of mutation-related capabilities a
 
 *      One increment would be to add aliasing or passing by reference, as illustrated above. In the illustration, we relied on the combination of passing by reference and mutation to demonstrate how you could get different behavior depending on whether an argument was passed to a function by reference or instead passed in the more familiar way (called "passing by value"). However, it would be possible to have passing by reference in a language without having mutation. For it to make any difference whether an argument is passed by reference or by value, such a language would have to have some primitive predicates which are sensitive to whether their arguments are aliased or not. In Jim's paper linked above, he calls such predicates "hyper-evaluative."
 
-       The simplest such predicate we might call "hyperequals": `y hyperequals w` should evaluate to true only when the arguments `y` and `w` are aliased.
+       The simplest such predicate we might call "hyperequals": `y hyperequals w` should evaluate to true when and only when the arguments `y` and `w` are aliased.
 
 
 *      Another increment would be to add implicit-style mutable variables, as we explained above. You could do this with or without also adding passing-by-reference.
@@ -602,9 +619,9 @@ Programming languages tend to provide a bunch of mutation-related capabilities a
 
        So we have here the basis for introducing a new kind of equality predicate into our language, which tests not for qualitative indiscernibility but for numerical equality. In OCaml this relation is expressed by the double equals `==`. In Scheme it's spelled `eq?` Computer scientists sometimes call this relation "physical equality". Using this equality predicate, our comparison of `ycell` and `xcell` will be `false`, even if they then happen to contain the same `int`.
 
-       Isn't this interesting? Intuitively, elsewhere in math, you might think that qualitative indicernibility always suffices for numerical identity. Well, perhaps this needs discussion. In some sense the imaginary numbers ι and -ι are qualitatively identical, but numerically distinct. However, arguably they're not *fully* qualitatively identical. They don't both bear all the same relations to ι for instance. But then, if we include numerical identity as a relation, then `ycell` and `xcell` don't both bear all the same relations to `ycell`, either. Yet there is still a useful sense in which they can be understood to be qualitatively equal---at least, at a given stage in a computation.
+       Isn't this interesting? Intuitively, elsewhere in math, you might think that qualitative indicernibility always suffices for numerical identity. Well, perhaps this needs discussion. In some sense the imaginary numbers ι and -ι are qualitatively indiscernible, but numerically distinct. However, arguably they're not *fully* qualitatively indiscernible. They don't both bear all the same relations to ι for instance. But then, if we include numerical identity as a relation, then `ycell` and `xcell` don't both bear all the same relations to `ycell`, either. Yet there is still a useful sense in which they can be understood to be qualitatively equal---at least, at a given stage in a computation.
 
-       Terminological note: in OCaml, `=` and `<>` express the qualitative (in)discernibility relations, also expressed in Scheme with `equal?`. In OCaml, `==` and `!=` express the numerical (non)identity relations, also expressed in Scheme with `eq?`. `=` also has other syntactic roles in OCaml, such as in the form `let x = value in ...`. In other languages, like C and Python, `=` is commonly used just for assignment (of either of the sorts we've now seen: `let x = value in ...` or `change x to value in ...`). The symbols `==` and `!=` are commonly used to express qualitative (in)discernibility in these languages. Python expresses numerical (non)identity with `is` and `is not`. What an unattractive mess. Don't get me started on Haskell (qualitative non-identity is `/=`) and Lua (physical (non)identity is `==` and `~=`).
+       Terminological note: in OCaml, `=` and `<>` express the qualitative (in)discernibility relations, also expressed in Scheme with `equal?`. In OCaml, `==` and `!=` express the numerical (non)identity relations, also expressed in Scheme with `eq?`. `=` also has other syntactic roles in OCaml, such as in the form `let x = value in ...`. In other languages, like C and Python, `=` is commonly used just for assignment (of either of the sorts we've now seen: `let x = value in ...` or `change x to value in ...`). The symbols `==` and `!=` are commonly used to express qualitative (in)discernibility in these languages. Python expresses numerical (non)identity with `is` and `is not`. What an unattractive mess. Don't get me started on Haskell (qualitative discernibility is `/=`) and Lua (physical (non)identity is `==` and `~=`).
 
        Note that neither of the equality predicates here being considered are the same as the "hyperequals" predicate mentioned above. For example, in the following (fictional) language:
 
@@ -625,7 +642,7 @@ Programming languages tend to provide a bunch of mutation-related capabilities a
                xcell == wcell
                xcell == zcell
 
-       If we express qualitative identity using `=`, as OCaml does, then all of the salient comparisons would be true:
+       If we express qualitative indiscernibility using `=`, as OCaml does, then all of the salient comparisons would be true:
 
                ycell = wcell
                ycell = zcell
@@ -658,19 +675,20 @@ Programming languages tend to provide a bunch of mutation-related capabilities a
                in let (adder', setter') = factory 1
                in ...
 
-       Of course, in most languages you wouldn't be able to evaluate a comparison like `getter = getter'`, because in general the question whether two computations always return the same values for the same argument is not decidable. So typically languages don't even try to answer that question. However, it would still be true that `getter` and `getter'` (and `adder` and `adder'`) were extensionally equivalent.
+       Of course, in most languages you wouldn't be able to evaluate a comparison like `getter = getter'`, because in general the question whether two functions always return the same values for the same arguments is not decidable. So typically languages don't even try to answer that question. However, it would still be true that `getter` and `getter'` (and `adder` and `adder'`) were extensionally equivalent.
 
        However, they're not numerically identical, because by calling `setter 2` (but not calling `setter' 2`) we can mutate the function value `getter` (and `adder`) so that it's *no longer* qualitatively indiscernible from `getter'` (or `adder'`).
 
 
  
-*      A fourth grade of mutation involvement...
+*      A fourth grade of mutation involvement: (--- FIXME ---)
 
        structured references
         (a) if `a` and `b` are mutable variables that uncoordinatedly refer to numerically the same value
             then mutating `b` won't affect `a` or its value
         (b) if however their value has a mutable field `f`, then mutating `b.f` does
             affect their shared value; will see a difference in what `a.f` now evaluates to
+               (c) examples: Scheme mutable pairs, OCaml mutable arrays or records