week9 tweak
[lambda.git] / week9.mdwn
index abff587..76f4038 100644 (file)
@@ -2,7 +2,7 @@
 
 The seminar is now going to begin talking about more **imperatival** or **effect**-like elements in programming languages. The only effect-like element we've encountered so far is the possibility of divergence, in languages that permit fixed point combinators and so have the full power of recursion. What it means for something to be effect-like, and why this counts as an example of such, will emerge.
 
-Other effect-like elements in a language include: printing (recall the [[damn]] example at the start of term); continuations (also foreshadowed in the [[damn]] example) and exceptions (foreshadowed in our discussion of abortable list traversals in [[week4]]); and **mutation**. This last notion is our first topic.
+Other effect-like elements in a language include: printing (recall the [[damn]] example at the start of term); continuations (also foreshadowed in the [[damn]] example) and exceptions (foreshadowed in our discussion of abortable list traversals in [[week4]]); and **mutation**. This last notion is our topic this week.
 
 
 ## Mutation##
@@ -37,7 +37,7 @@ If the expression that evaluates to a function value has a free variable in it,
 
 Other choices about how to interpret free variables are also possible (you can read about "lexical scope" versus "dynamic scope"), but what we do here is the norm in functional programming languages, and seems to be easiest for programmers to reason about.
 
-In our next fragement, we re-use a variable that had been bound to another value in a wider context:
+In our next fragment, we re-use a variable that had been bound to another value in a wider context:
 
        [E] let x be 4 in
                  let x be 3 in
@@ -99,9 +99,9 @@ When dealing with explicit-style mutation, there's a difference between the type
 
 ##Controlling order##
 
-When we're dealing with mutable variables (or any other kind of effect), order matters. For example, it would make a big difference whether I evaluated "let z = !ycell" before or after evaluating "ycell := !ycell + 1". Before this point, order never mattered except with respect to sometimes avoiding divergence.
+When we're dealing with mutable variables (or any other kind of effect), order matters. For example, it would make a big difference whether I evaluated `let z = !ycell` before or after evaluating `ycell := !ycell + 1`. Before this point, order never mattered except sometimes it played a role in avoiding divergence.
 
-OCaml does not however guarantee what order expressions will be evaluated in arbitrary contexts. For example, in the following fragment, you cannot rely on `expression_a` being evaluated before `expression_b` before `expression_c`:
+OCaml does *not* guarantee what order expressions will be evaluated in arbitrary contexts. For example, in the following fragment, you cannot rely on `expression_a` being evaluated before `expression_b` before `expression_c`:
 
        let triple = (expression_a, expression_b, expression_c)
 
@@ -161,7 +161,7 @@ How could such functions be useful? Well, as always, the context in which you bu
        in f ()
        in z;;
 
-We don't apply (or call or execute or however you want to say it) the function `f` until after we've extracted `ycell`'s value and assigned it to `z`. So `z` will get assigned to 1. If on the other hand we called `f ()` before evaluating `let z = !ycell`, then `z` would have gotten assigned a different value.
+We don't apply (or call or execute or however you want to say it) the function `f` until after we've extracted `ycell`'s value and assigned it to `z`. So `z` will get assigned 1. If on the other hand we called `f ()` before evaluating `let z = !ycell`, then `z` would have gotten assigned a different value.
 
 In languages with mutable variables, the free variables in a function definition are usually taken to refer back to the same *reference cells* they had in their lexical contexts, and not just their original value. So if we do this for instance:
 
@@ -172,15 +172,15 @@ In languages with mutable variables, the free variables in a function definition
                in let setter (new_value : int) =
                        free_var := new_value
                in (getter, setter)
-       in let (getter1, setter1) = factory 1
-       in let first = getter1 ()
-       in let () = setter1 2
-       in let second = getter1 ()
-       in let () = setter1 3
-       in let third = getter1 ()
+       in let (getter, setter) = factory 1
+       in let first = getter ()
+       in let () = setter 2
+       in let second = getter ()
+       in let () = setter 3
+       in let third = getter ()
        in (first, second, third)
        
-At the end, we'll get `(1, 2, 3)`. The reference cell that gets updated when we call `setter1` is the same one that gets fetched from when we call `getter1`. This should seem very intuitive here, since we're working with explicit-style mutation. When working with a language with implicit-style mutation, it can be more surprising. For instance, here's the same fragment in Python, which has implicit-style mutation:
+At the end, we'll get `(1, 2, 3)`. The reference cell that gets updated when we call `setter` is the same one that gets fetched from when we call `getter`. This should seem very intuitive here, since we're working with explicit-style mutation. When working with a language with implicit-style mutation, it can be more surprising. For instance, here's the same fragment in Python, which has implicit-style mutation:
 
        def factory (starting_value):
                free_var = starting_value
@@ -193,26 +193,26 @@ At the end, we'll get `(1, 2, 3)`. The reference cell that gets updated when we
                        nonlocal free_var
                        free_var = new_value
                return getter, setter
-       getter1, setter1 = factory (1)
-       first = getter1 ()
-       setter1 (2)
-       second = getter1 ()
-       setter1 (3)
-       third = getter1 ()
+       getter, setter = factory (1)
+       first = getter ()
+       setter (2)
+       second = getter ()
+       setter (3)
+       third = getter ()
        (first, second, third)
 
-Here, too, just as in the OCaml fragment, all the calls to getter1 and setter1 are working with a single mutable variable `free_var`.
+Here, too, just as in the OCaml fragment, all the calls to getter and setter are working with a single mutable variable `free_var`.
 
 If however you called `factory` twice, you'd have different `getter`/`setter` pairs, each of which had their own, independent `free_var`. In OCaml:
 
        let factory (starting_val : int) =
        ... (* as above *)
-       in let (getter1, setter1) = factory 1
-       in let (getter2, setter2) = factory 1
-       in let () = setter1 2
-       in getter2 ()
+       in let (getter, setter) = factory 1
+       in let (getter', setter') = factory 1
+       in let () = setter 2
+       in getter' ()
 
-Here, the call to `setter1` only mutated the reference cell associated with the `getter1`/`setter1` pair. The reference cell associated with `getter2` hasn't changed, and so `getter2 ()` will still evaluate to 1.
+Here, the call to `setter` only mutated the reference cell associated with the `getter`/`setter` pair. The reference cell associated with `getter'` hasn't changed, and so `getter' ()` will still evaluate to 1.
 
 Notice in these fragments that once we return from inside the call to `factory`, the `free_var` mutable variable is no longer accessible, except through the helper functions `getter` and `setter` that we've provided. This is another way in which a thunk like `getter` can be useful: it still has access to the `free_var` reference cell that was created when it was, because its free variables are interpreted relative to the context in which `getter` was built, even if that context is otherwise no longer accessible. What `getter ()` evaluates to, however, will very much depend on *when* we evaluate it---in particular, it will depend on which calls to the corresponding `setter` were evaluated first.