Merge branch 'master' into working
authorJim <jim.pryor@nyu.edu>
Thu, 5 Feb 2015 18:09:31 +0000 (13:09 -0500)
committerJim <jim.pryor@nyu.edu>
Thu, 5 Feb 2015 18:09:31 +0000 (13:09 -0500)
* master:
  next chunk of content
  add #funct-declarations
  starting lambda calculus intro
  remove notes on git
  add #guards and #as-patterns anchors
  add #sections anchor
  add toc
  add anchor for #variables
  Notes for understanding git

rosetta1.mdwn
topics/_week2.mdwn
topics/_week2_lambda_calculus_intro.mdwn [new file with mode: 0644]
topics/week1.mdwn
topics/week1_advanced_notes.mdwn

index 5e9c052..4576a9b 100644 (file)
@@ -39,9 +39,13 @@ These block comments also nest. Another form of block comments is `#;( ... )`. T
 
 
 
-### Variable names
+### Variables
 
-% Haskell's division into letter-based vs operators. Each can be "flagged" to temporarily behave as though it belonged to the other syntactic category (see below).
+Our [[syntax for variables|topics/week1#variables]] in Kapulet is close to that in the other languages. Haskell and OCaml differ only in that they do not permit trailing `?` or `!`; however, they do permit trailing `'`s (and even permit `'`s *in the middle* of a variable too, which Kapulet does not). Scheme permits all of these characters, plus many more punctuation symbols as well, to occur anywhere in a variable. Scheme also permits variables to begin with capital letters, or to consist solely of the single character `_`; but the other languages reserve these terms for special purposes.
+
+In addition to the variables made of letters (more properly, of alphanumerics), Haskell and OCaml and Kapulet also permit some variables made exclusively of punctuation symbols, like `<` or Haskell's `>=>` and `<$>`. In Haskell, these always have infix syntax, and the variables made of letters never do. (But the former can have their infix syntax suppressed with parentheses, and the latter can be "flagged" to temporarily take on infix syntax, as we'll discuss below.)
+
+In OCaml and Kapulet, some variables made of letters also have infix syntax, such as `comp` in Kapulet or `mod` in OCaml. I haven't presented to you the complex mechanisms needed to declare this.
 
 
 
@@ -56,9 +60,9 @@ not:
 
     + 1 2
 
-Although all three of these languages permits you to enclose an infix operator in parentheses to make a *section*, which no longer has infix syntax. In Kapulet, `( + )` is the same as &lambda; `(x, y). x + y`, whereas in OCaml and Haskell it's a *curried* function, which we can write (in Kapulet syntax) as &lambda; `x y. x + y`.
+Although all three of these languages permits you to enclose an infix operator in parentheses to make a *section*, which no longer has infix syntax. In Kapulet, `( + )` is the same as &lambda; `(x, y). x + y`, whereas in OCaml and Haskell it's a *curried* function, which we can write (in Kapulet syntax) as &lambda; `x y. x + y`. We'll discuss sections and curried functions below.
 
-Kapulet and OCaml have some operators spelled with letters also taking infix syntax, such as `comp` in Kapulet or `mod` in OCaml. In Haskell, this is never the case: variables that are made of letters are only treated as function terms being applied to arguments *when they're at the start* of a list of expressions; and variables that are made of punctuation symbols, and not enclosed in parentheses, will only be treated as infix operators. However, Haskell permits you to temporarily "flag" a letter-made function term to behave like an infix operator, by enclosing it in `` ` `` marks. Thus in Haskell you can write:
+Kapulet and OCaml have some operators spelled with letters also taking infix syntax, such as `comp` in Kapulet or `mod` in OCaml. In Haskell, this is never the case: variables that are made of letters are only treated as function terms being applied to arguments *when they're at the start* of a list of expressions; and variables that are made of punctuation symbols, and not enclosed in parentheses, will only be treated as infix operators. However, Haskell permits you to temporarily "flag" a  function term made of letters to behave like an infix operator, by enclosing it in `` ` `` marks. Thus in Haskell you can write:
 
     3 `mod` 2
 
@@ -72,13 +76,16 @@ and the like. Moreover, in Scheme parentheses are never optional and never redun
 
     ((+) 3 2)
 
-what that would mean is that `+` is first being applied to *zero* arguments, which is different from not applying it all. (In Kapulet, OCaml, and Haskell, one would write that `f` is being applied to "zero arguments" like this: `f ()`.) Scheme helpfully defines the result of applying `+` to zero arguments to be `0`. So `((+) 3 2)` would evaluate to whatever `(0 3 2)` does, and that's an error, because `0` is not a function.
+what that would mean is that `+` is first being applied to *zero* arguments, which is different from not applying it all. (In Kapulet, OCaml, and Haskell, one would write that `f` is being applied to "zero arguments" like this: `f ()`. FIXME) Scheme helpfully defines the result of applying `+` to zero arguments to be `0`. So `((+) 3 2)` would evaluate to whatever `(0 3 2)` does, and that's an error, because `0` is not a function.
 
-Note that `(0 3 2)`, although it *is*, qua expression, a list of numbers, does not evaluate to a list. To get an expression that *evaluates to* that list, you'd have to use `(list 0 3 2)` or `'(0 3 2)`. (Notice the initial `'`.)
+Note that `(0 3 2)`, although it *is*, qua expression, a list of numbers, does not evaluate to a list. To get an expression that *evaluates to* that list, you'd have to use `(list 0 3 2)` or `'(0 3 2)`. (Notice the initial `'`.) FIXME
 
 In Scheme, you can also write `(+ 3 2 10)`, and so on. You only have to write `(+ (+ 3 2) 10)` if you really want to.
 
-% Parentheses have other roles in Scheme, too.
+Parentheses have many other roles in Scheme, as well; they're a ubiquitous part of the syntax, and don't always express function application. You might sometimes feel they are overused.
+
+You may sometimes see `[ ... ]` being used instead of `( ... )`. This is just a stylistic variant, they work exactly the same. The official Scheme standard doesn't permit that, but most Scheme implementations do. It can help keep track of which closing `]` or `)` goes with which opening `[` or `)`. The opening and closing symbols always have to correspond.
+
 
 In Scheme, the default style for defining functions is as taking several arguments simultaneously, that is the *uncurried* style. In OCaml and Haskell, the default style is to define them *curried*. Curried functions can easily be partially applied:
 
@@ -112,12 +119,13 @@ Here the last displayed line will fail, because `add` expects as its argument a
 
 Kapulet essentially works like OCaml and Haskell; though for pedagogical reasons I started out by introducing uncurried definitions, rather than the *curried* definitions those other languages predominantly use.
 
-As we mentioned, in Kapulet, OCaml, and Haskell, there is a shorthand that enables you to write things like:
+[[As we mentioned|topics/week1_advanced_notes#sections]], in Kapulet, OCaml, and Haskell, there is a shorthand that enables you to write things like:
 
     # Kapulet
     let
       ten_minus match lambda x. 10 - x;
-      and_ys    match lambda x. x & ys
+      and_ys    match lambda x. x & ys;
+      plus      match lambda (x, y). x + y
     in (ten_minus, and_ys)
 
 like this:
@@ -125,7 +133,8 @@ like this:
     # Kapulet
     let
       ten_minus match (10 - );
-      and_ys    match ( & ys)
+      and_ys    match ( & ys);
+      plus      match ( + )
     in (ten_minus, and_ys)
 
 There are just minor differences between these languages. First, OCaml doesn't have the `( + 10)` or `(10 + )` forms, but only the `( + )`. Second, as a special case, OCaml doesn't permit you to do this with its list-consing operator `::`. You have to write `fun x xs -> x :: xs`, not `( :: )`. Whereas in Kapulet `( & )`, `(x & )`, and `( & xs)` are all sections using its sequence-consing operator `&`; and in Haskell, `( : )`, `(x : )`, and `( : xs)` are the same.
@@ -156,13 +165,23 @@ I know all these languages fairly well, and I still find this last issue difficu
 
 The relation that's written `==` in Kapulet is also written that way in Haskell. That symbol means something else in OCaml, having to do with mutable reference cells; to get the same notion in OCaml one writes just a single `=`. The negation of this notion is written `!=` in Kapulet, `/=` in Haskell, and `<>` in OCaml. (Again, `!=` means something else in OCaml.)
 
-The relations that are written `and`, `or`, and `not` are written in Haskell and OCaml as `&&`, `||`, and `not`. (Haskell uses `and` and `or` to express functions that form the conjunction or disjunction of every `Bool` value in a List of such. OCaml permits `or` as an old synonym for `||`, but discourages using that spelling. OCaml also permits `&` as an old, discouraged synonym for `&&`.)
+The relations that are written `and`, `or`, and `not` in Kapulet are written the same way in Scheme. Note that in Scheme the first two can take zero or more arguments:
+
+    ; Scheme
+    (and)
+    (and bool1)
+    (and bool1 bool2)
+    (and bool1 bool2 bool3)
+
+As you'd expect `(and bool1)` evaluates the same as plain `bool1`; similarly with `(or bool1)`. What do you think `(and)` with no arguments should evaluate to? How about `(or)`?
 
-Scheme %%
+These relations are written in Haskell and OCaml as `&&`, `||`, and `not`. (Haskell uses `and` and `or` to express functions that form the conjunction or disjunction of every `Bool` value in a List of such. OCaml permits `or` as an old synonym for `||`, but discourages using that spelling. OCaml also permits `&` as an old, discouraged synonym for `&&`.)
 
 The values that are written `'true` and `'false` in Kapulet are written in Haskell as `True` and `False`, and in OCaml as just `true` and `false`. They're written `#t` and `#f` in Scheme, but in Scheme in many contexts any value that isn't `#f` will behave as though it were `#t`, even values you might think are more "false-ish", like `0` and the empty list. Thus `(if 0 'yes 'no)` will evaluate to `'yes`.
 
-Scheme recognizes the values `'true` and `'false`, but it treats `'false` as distinct from `#f`, and thus as a "true-ish" value, like all of its other values that aren't `#f`.
+Some Scheme implementations, such as Racket, permit `#true` and `#false` as synonyms for `#t` and `#f`.
+
+Scheme also recognizes the values `'true` and `'false`, but it treats `'false` as distinct from `#f`, and thus as a "true-ish" value, like all of its other values that aren't `#f`. Kapulet essentially took Scheme's `boolean` values and collapsed them into being a subtype of its `symbol` values. FIXME also with chars.
 
 
 
@@ -216,8 +235,8 @@ Here are some list functions in Kapulet:
     dropwhile
     reverse
     # new functions
-    concat       # converts [[10, 20], [30], [], [40, 50]]
-                 # to [10, 20, 30, 40, 50] (only merging a single layer of []s)
+    join         # converts [[10, 20], [30], [], [40, 50]]
+                 # to [10, 20, 30, 40, 50] (but only "joining" a single layer of []s)
     (mem)        # infix syntax, 2 mem [1, 2, 3] == 'true
     nth          # nth [10, 20, 30] 1 == 20, because the first element
                  # is at position 0; fails if index is out of bounds
@@ -241,11 +260,12 @@ Here are the corresponding functions in Haskell:
     map
     zipWith  {- zip handles the special case where f is the function that forms ordered pairs
                 both zipWith and zip stop with the shortest list -}
-    unzip    -- doesn't take an f argument, assumes (\(x, y) -> (x, y))
+    unzip    {- unlike unmap2, doesn't take an explicit f argument
+                just assumes it's (\(x, y) -> (x, y)) -}
     takeWhile
     dropWhile
     reverse
-    concat
+    concat   -- corresponding to join
     elem     -- not infix syntax, but often written as: 2 `elem` [1, 2, 3]
     (!!)     -- infix syntax: [10, 20, 30] !! 1 == 20; fails if index is out of bounds
     all p xs
@@ -269,14 +289,14 @@ Here they are in OCaml:
     List.split   (* like Haskell's unzip, doesn't take an f argument *)
     (* no function corresponding to takewhile or dropwhile *)
     List.rev
-    List.concat  (* also List.flatten, which still only merges a single layer of []s *)
+    List.concat  (* also List.flatten, which still only "joins" a single layer of []s *)
     List.mem     (* not infix syntax *)
     List.nth     (* List.nth [10; 20; 30] 1 = 20; fails if index is out of bounds *)
     List.for_all p xs
     List.exists p xs
 
 
-How does all this look in Scheme? Well, Scheme has a notion they call a (proper) `list`, and also a notion they call a `vector`. There are also what Scheme calls "improper" `list`s, with `(cons 1 'nonlist)` or `'(1 . nonlist)`, where `'nonlist` is any non-list (here it's a `symbol`) being a special case. Let's ignore the improper `list`s. Scheme's (proper) `list`s and `vector`s each has a claim to correspond to Kapulet's sequences, Haskell's Lists, and OCaml's `list`s. Each is also somewhat different. The dominant differences are:
+How does all this look in Scheme? Well, Scheme has a notion they call a (proper) `list`, and also a notion they call a `vector`. There are also what Scheme calls "improper" `list`s, with `(cons 1 'nonlist)` or `'(1 . nonlist)`, where `'nonlist` is any non-list (here it's a `symbol`) being a limiting case. Let's ignore the improper `list`s. Scheme's (proper) `list`s and `vector`s each has a claim to correspond to Kapulet's sequences, Haskell's Lists, and OCaml's `list`s. Each is also somewhat different. The dominant differences are:
 
 1.  these structures in Scheme can contain heterogenously-typed elements, including further `list`s and `vector`s in some positions but not in others
 2.  in the official Scheme standard, `list`s and `vector`s are both *mutable* containers, that is, one and the same persisting `list` structure can have different
@@ -320,7 +340,7 @@ Here are the `list` functions in Scheme corresponding to the functions listed in
                       ; can take one or more list arguments
     ; no official function corresponding to unmap2 or takewhile or dropwhile
     reverse
-    ; no official function corresponding to concat
+    ; no official function corresponding to join/concat
     member            ; corresponds to Kapulet's (mem) and Haskell's elem
     (list-ref xs k)   ; corresponds to Kapulet's `nth xs k`
     ; no official function corresponding to all or any
@@ -329,9 +349,382 @@ All of the functions listed as missing from the official Scheme standard can be
 
 
 
+### Pattern-matching
+
+The complex expression that's written like this in Kapulet:
+
+    # Kapulet
+    case some_expression of
+      0 then result0;
+      1 then result1;
+      x then resultx
+    end
+
+is written very similarly in Haskell:
+
+    -- Haskell
+    case some_expression {
+      0 -> result0;
+      1 -> result1;
+      x -> resultx
+    }
+
+Unlike the other languages we're discussing, Haskell pays special attention to the whitespace/indentation of what you write. This permits you to omit the `{`, `;`, and `}`s in the above, if you've got the indentation right. And that's how you will often see Haskell code displayed. On this website, though, I propose to always include the `{`s and so on when displaying Haskell code, because the indentation rules aren't 100% intuitive. It's easy to read properly-indented Haskell code, but until you've learned and practiced the specific rules, it's not always easy to write it.
+
+This is written only a little bit differently in OCaml:
+
+    (* OCaml *)
+    match some_expression with
+      0 -> result0 |
+      1 -> result1 |
+      x -> resultx
+
+Note there is no closing `end` or `}`. You can enclose the whole expression in parentheses if you want to, and when embedding it in some larger expressions (like another `match` expression), you may need to. Sometimes the `|` dividers are written at the start of a line, and you are allowed to include an extra one before the first line, so you could also see this written as:
+
+    (* OCaml *)
+    match some_expression with
+      | 0 -> result0
+      | 1 -> result1
+      | x -> resultx
+
+The syntax for [[guards|topics/week1_advanced_notes#guards]] and [[as-patterns|topics/week1_advanced_notes#as-patterns]] also only varies slightly between these languages:
+
+    # Kapulet
+    case some_expression of
+      pat1   when guard             then result1;
+      pat1   when different_guard   then result2;
+      ((complex_pat) as var, pat4)  then result3
+    end
+
+    -- Haskell
+    case some_expression {
+      pat1 | guard              -> result1;
+           | different_guard    -> result2;
+      (var@(complex_pat), pat4) -> result3
+    }
+
+    (* OCaml *)
+    match some_expression with
+      pat1   when guard             -> result0 |
+      pat1   when different_guard   -> result1 |
+      ((complex_pat) as var, pat4   -> result3
+
+
+The official Scheme standard only provides for a limited version of this. There is a `case` construction, available since at least "version 5" of the Scheme standard (r5rs), but it only accepts literal values as patterns, not any complex patterns containing them or any patterns containing variables. Here is how it looks:
+
+    ; Scheme
+    (case some_expression
+      ((0) 'result0)
+      ((1) 'result1)
+      ((2 3 5) 'smallprime)
+      (else 'toobig))
+
+The results can be complex expressions; I just used bare symbols here for illustration. Note that the literal patterns in the first two clauses are surrounded by an extra pair of parentheses than you might expect. The reason is shown in the third clause, which begins `(2 3 5)`. This does not mean to match a list containing the values `2` `3` and `5`. Instead it means to match the simple value `2` *or* the simple value `3` *or* the simple value `5`. The final `else` clause is optional.
+
+The patterns here can be any literal value (what the Scheme standards call a "datum"). Numbers are permitted, as are boolean literals (`#t` and `#f`) and symbolic atoms (`'alpha` and the like, though inside a pattern position in a `case`-expression, you omit the initial `'`). You can also use the list literal `'()` (again, omit the initial `'` when writing it as a pattern). Some implementations of Scheme allow more complex list patterns, matching literal lists like `'(alpha 0 () #t)`; others don't.
+
+There are various add-on libraries to Scheme that will permit you to pattern-match in more ambitious ways, approximating what you can do in Kapulet, OCaml, and Haskell. We will explain some of these later, after we've introduced you to the notion of *datatypes*.
+
+What programmers using standard Scheme tend to do instead is to use *predicates* that query the type and/or structure of an unknown value, and then take separate evaluation paths depending on the result. This can be done with an `if...then...else...` construction, or with Scheme's more general `cond` construction. In Scheme, these two are equivalent:
+
+    ; Scheme
+    (if test1 'result1
+              (if test2 'result2
+                        (if test3 'result3 'somethingelse)))
+
+    (cond
+      (test1 'result1)
+      (test2 'result2)
+      (test3 'result3)
+      (else  'somethingelse))
+
+The tests tend to use predicates like `null?` (are you the empty list?), `pair?` (are you a non-empty list, whether proper or improper?), `list?` (are you a proper list, whether empty or not?), `symbol?`, `boolean?`, `number?`, `zero?` (you get the idea). But you can also use more complex tests you write on the spot, or use antecedently-defined functions:
+
+    ; Scheme...in case the parens left any doubt
+    (define smallprime? (lambda (x) (if (= x 2) #t (if (= x 3) #t (if (= x 5) #t #f)))))
+
+    (cond
+      ((= x 0) 'infant)
+      ((smallprime? x) 'myfavorite)
+      ((and (> x 10) (< x 20)) 'teenaged)
+      (else 'unknown))
+
+Remember that in Scheme, an expression doesn't have to evaluate to `#t` to be treated as "truth-like". *Every* value other than `#f` is treated as truth-like. So `(if 0 'zero 'nope)` evaluates to `'zero`.
+
+You may sometimes see Scheme `cond` constructions written with this kind of clause:
+
+    (cond
+      ...
+      (test-expression => function-value)
+      ...)
+
+That's the same as the following:
+
+    (cond
+      ...
+      (test-expression (function-value test-expression))
+      ...)
+
+Except that it only evaluates the test-expression once.
+
+The clauses in Scheme's `cond` expressions can contain *multiple* expressions after the test. This only becomes useful when you're working with mutable values and side-effects, which we've not gotten to yet. The `if` expressions only take a single expression for the "then" branch and a single expression for the "else" branch. You can turn a complex series of expressions, which may involve side-effects, into a single expression by wrapping it in a `(begin ...)` construction. The `(begin ...)` construction as a whole evaluates to whatever the last expression it contains does.
+
+Scheme standards after r5rs also provide two further conditional constructions, which are for the situations where you want to perform a meaningful action only on the "then" branch, or only on the "else" branch:
+
+    (when test-expression
+       result-expression1...)
+
+    (unless test-expression
+       result-expression2...)
+
+If the test-expression evaluates to `#f`, then the `when` expression evaluates to a special "void" value; mutatis mutandis for the `unless` expression. This is analogous to `()` in OCaml, Haskell, and Kapulet.
+
+In the last three languages, the expressions in the then-branch and the else-branch of a conditional have to have the same type. You can't say `if test-expression then 0 else []`. Also, they expect the test-expression to evaluate specifically to a boolean value, not merely to `'false` or *anything else*. They are stricter about types here than Scheme is.
+
+In the special case where both a then-branch and an else-branch evaluate to `()`, and the else-branch involves no complex expression but merely the literal `()`, then OCaml permits you to omit the else-branch. So in OCaml you can write this:
+
+     if test-expression then then-result
+
+instead of
+
+     if test-expression then then-result else ()
+
+This is similar to Scheme's `when`-expression. Kapulet and Haskell have no analogue.
+
+
+
+### Lambda expressions
+
+In Kapulet you write &lambda;-expressions (sometimes called "anonymous functions") with a prefix of either &lambda; or the spelled-out `lambda`. That's followed by one or more patterns, separated by spaces, then a period, then a single expression which makes up the body of the function. When there are multiple patterns, the function expressed is *curried*, thus:
+
+    lambda (x, y) z. result
+
+means the same as:
+
+    lambda (x, y). (lambda z. result)
+
+The parentheses could have been omitted around `lambda z. result`; they're just there to focus your attention.
+
+Haskell and OCaml are very similar to this, they just use some slightly different notation. In Haskell you'd write:
+
+    -- Haskell
+    \(x, y) z -> result
+
+and in OCaml you'd write:
+
+    (* OCaml *)
+    fun (x, y) z -> result
+
+You may sometimes see &lambda;-expressions in OCaml written using `function` instead of `fun`. These overlap somewhat in their usage. The difference is that `function` only allocates a position for *one* argument pattern, so can't define curried functions. On the other hand, `function` can take multiple *variant* patterns for that single position. Thus with `function` you can say:
+
+    (* OCaml *)
+    function []    -> result1 |
+             x::xs -> result2
+
+whereas with `fun` you'd have to write:
+
+    (* OCaml *)
+    fun ys -> match ys with
+                []    -> result1 |
+                x::xs -> result2
+
+In Scheme, lambda expressions are written like this:
+
+    ; Scheme
+    (lambda (vars...) body-expressions...)
+
+Scheme only permits simple variables as its argument patterns here, and the lambda-expression can be defined with zero or more arguments:
+
+    ; Scheme
+    (lambda () ...)
+    (lambda (x) ...)
+    (lambda (x y) ...)
+    (lambda (x y z) ...)
+
+There is special syntax for defining functions that may take varying numbers of arguments (recall `and` and `+`), to have them bind a single variable to a list containing all of their arguments (or all of the arguments after the third...). I won't explain that syntax here.
+
+
+
+### Let, Letrec, and Define
 
+Kapulet has the syntax:
 
-<!--
+    # Kapulet
+    let
+      pat1  match expr1;
+      pat2  match expr2;
+      pat3  match expr3
+    in result
+
+which is equivalent to:
+
+    # Kapulet
+    let
+      pat1  match expr1
+    in let
+      pat2  match expr2
+    in let
+      pat3  match expr3
+    in result
+
+There is also a `letrec` form. In `let`, the bindings in `pat1` are in effect for the evaluation of all of `expr2`, `expr3`, and `result` (but not any further, if this is part of a more complex expression); similarly for the bindings in `pat2` and `pat3`. In `letrec`, all of the bindings on the left-hand side are in effect for all of the right-hand side expressions, as well as for the result.
+
+OCaml only has the second, more verbose form of this, and writes it a bit differently:
+
+    (* OCaml *)
+    let
+      pat1  = expr1
+    in let
+      pat2  = expr2
+    in let
+      pat3  = expr3
+    in result
+
+If you want to define some mutually recursive functions with `letrec`, there's a special syntax for that, using `letrec ... and ... in ...`:
+
+    (* OCaml *)
+    letrec
+      even  = fun x -> if x = 0 then true else odd x
+    and
+      odd   = fun x -> if x = 0 then false else even x
+    in ...
+
+Haskell has both of the syntactic forms that Kapulet does, though like OCaml, it uses `=` rather than `match`. And it wraps all multiple patterns with `{ ... }` (see earlier remarks about Haskell and whitespace/indentation FIXME):
+
+    -- Haskell
+    let {
+      pat1  = expr1;
+      pat2  = expr2;
+      pat3  = expr3
+    } in result
+
+Also, in Haskell `let` always means `letrec`. There is no term in Haskell that means what simple `let` does in Kapulet and OCaml.
+
+Scheme has *four or five* syntactic forms here, including `let`, `let*`, `letrec`, and `letrec*`. The difference between the last two [is subtle](http://stackoverflow.com/questions/13078165) and only arises in the presence of continuations; you can just use `letrec` for ordinary purposes. I won't try to explain the difference between `let` and `let*` here, except to say this:
+
+1.  When there's only a single pattern-binding clause, as in `(let ((var expression)) result)`, `let` and `let*` work the same.
+2.  When there are multiple pattern-binding clauses, as in `(let ((var1 expression1) (var2 expression2)) result)`, then they work somewhat differently and `let*` is probably the one that works like you're expecting.
+
+The `let*` form is the one that corresponds to `let` in Kapulet. I recommend you get in the habit of just always using `let*` (or `letrec`) in Scheme.
+
+When you're at the "toplevel" of your program, or of a library/module/compilation-unit (the terminology differs), there is also another syntactic form possible. In Kapulet, you'd write:
+
+    # Kapulet
+    let
+      pat1  match expr1;
+      ...
+    end
+    ... # rest of program or library
+
+Notice that this form ends with `end`, not with `in result`. The above is roughly equivalent to:
+
+    # Kapulet
+    let
+      pat1  match expr1;
+      ...
+    in ... # rest of program or library
+    
+That is, the bindings initiated by the clauses of the `let`-expression remain in effect until the end of the program or library. They can of course be "hidden" by subsequent bindings to new variables spelled the same way. The program:
+
+    # Kapulet
+    let
+      x  match 0
+    end
+    let
+      x  match 1
+    end
+    x
+
+evaluates to `1`, just like:
+
+    # Kapulet
+    let
+      x  match 0
+    in let
+      x  match 1
+    in x
+
+does. There's a similar form for `letrec`.
+
+OCaml can do the same:
+
+    let
+      x = 0;;
+    let
+      x = 1;;
+    x
+
+The double-semicolons are hints to OCaml's "toplevel interpreter" that a syntactic unit has finished. In some contexts they're not needed, but it does no harm to include them if you're not sure.
+
+Haskell's "toplevel interpreter" (ghci) permits a syntactic form that looks superficially quite like these:
+
+    let x = 2
+    x
+
+but under the covers something quite different is happening (you're working "inside the IO Monad", except that simple expressions like `x` that don't evaluate to monadic values are also evaluated, as a special case). If you're writing in a *file* that you want Haskell to interpret or compile, on the other hand, you have to do something a bit different (which you can't easily also do inside ghci). [[Recall|topics/week1_advanced_notes#funct-declarations]] the shortcut by which we permitted:
+
+    # Kapulet
+    let
+      f  match lambda pat1. body1;
+      g  match lambda pat2 pat3. body2;
+      ...
+
+to be written more concisely as:
+
+    # Kapulet
+    let
+      f pat1      = body1;
+      g pat2 pat3 = body2;
+      ...
+
+OCaml and Haskell permit that same shorthand. And what Haskell permits at the toplevel of *files* are just the bare binding clauses of such expressions, that is, without the surrounding `let` and `in ...`. That is, a Haskell file can look like this:
+
+    -- Haskell file.hs
+    f pat1      = body1
+
+    g pat2 pat3 = body2
+    ...
+
+Note there are no semicolons here. These are called "declarations" of the functions `f` and `g`. Note that a single function can have multiple declarations (within a single scoping context), using different patterns:
+
+    -- Haskell file.hs
+    f [] = 0
+    f (x:xs) = 1 + f xs
+
+defines `f` as a function that returns the length of a single List argument. (You can also do this *within* Haskell's `let`-constructions, too.) This is what corresponds *in Haskell files* to `let ... end` in Kapulet.
+
+Scheme has a version of `letrec ... end`, which it writes as `define`. Thus in Scheme this:
+
+    ; Scheme
+    (define var1 expr1)
+    ... ; rest of program
+
+evaluates the same as this:
+
+    ; Scheme
+    (letrec ((var1 expr1))
+            ... ; rest of program
+                )
+
+Some versions of Scheme permit you also to include `define` inside some (but not all) complex expressions. Thus you can write:
+
+    (lambda (x)
+      (define var1 expr1)
+      ...)
+
+instead of:
+
+    (lambda (x)
+      (letrec ((var1 expr1))
+      ...))
+
+There is no analogue to this in the other languages.
+
+
+
+
+
+FIXME
 
 symbol=?
 
@@ -355,7 +748,6 @@ Kapulet's `swap` (defined in homework) is Haskell's `Data.Tuple.swap`.
 
 Kapulet's `dup` isn't predefined in Haskell but can be easily expressed as `\x -> (x, x)`.
 
--->
 
 
 
@@ -363,6 +755,17 @@ Kapulet's `dup` isn't predefined in Haskell but can be easily expressed as `\x -
 
 (This page is being worked on...)
 
+
+
+### Further Installments ...
+
+We will expand these comparisons (on separate web pages) as we introduce additional ideas in the course, such as types and monads and continuations.
+
+
+
+
+
+
 FIXME
 
 
index c614319..7706eca 100644 (file)
@@ -10,241 +10,3 @@ Sometimes these notes will expand on things mentioned only briefly in class, or
 
 [Explanation of the "Damn" example shown in class](/damn)
 
-Basics of Lambda Calculus
-=========================
-
-The lambda calculus we'll be focusing on for the first part of the course has no types. (Some prefer to say it instead has a single type---but if you say that, you have to say that functions from this type to this type also belong to this type. Which is weird... In fact, though, such types are studied, under the name "recursive type." More about these later in the seminar.)
-
-Here is its syntax:
-
-<blockquote>
-<strong>Variables</strong>: <code>x</code>, <code>y</code>, <code>z</code>...
-</blockquote>
-
-Each variable is an expression. For any expressions M and N and variable a, the following are also expressions:
-
-<blockquote>
-<strong>Abstract</strong>: <code>(&lambda;a M)</code>
-</blockquote>
-
-We'll tend to write <code>(&lambda;a M)</code> as just `(\a M)`, so we don't have to write out the markup code for the <code>&lambda;</code>. You can yourself write <code>(&lambda;a M)</code> or `(\a M)` or `(lambda a M)`.
-
-<blockquote>
-<strong>Application</strong>: <code>(M N)</code>
-</blockquote>
-
-
-Examples of expressions:
-
-       x
-       (y x)
-       (x x)
-       (\x y)
-       (\x x)
-       (\x (\y x))
-       (x (\x x))
-       ((\x (x x)) (\x (x x)))
-
-The lambda calculus has an associated proof theory. For now, we can regard the
-proof theory as having just one rule, called the rule of **beta-reduction** or
-"beta-contraction". Suppose you have some expression of the form:
-
-       ((\a M) N)
-
-that is, an application of an abstract to some other expression. This compound form is called a **redex**, meaning it's a "beta-reducible expression." `(\a M)` is called the **head** of the redex; `N` is called the **argument**, and `M` is called the **body**.
-
-The rule of beta-reduction permits a transition from that expression to the following:
-
-       M [a:=N]
-
-What this means is just `M`, with any *free occurrences* inside `M` of the variable `a` replaced with the term `N`.
-
-What is a free occurrence?
-
->      An occurrence of a variable `a` is **bound** in T if T has the form `(\a N)`.
-
->      If T has the form `(M N)`, any occurrences of `a` that are bound in `M` are also bound in T, and so too any occurrences of `a` that are bound in `N`.
-
->      An occurrence of a variable is **free** if it's not bound.
-
-For instance:
-
-
->      T is defined to be `(x (\x (\y (x (y z)))))`
-
-The first occurrence of `x` in T is free.  The `\x` we won't regard as containing an occurrence of `x`. The next occurrence of `x` occurs within a form that begins with `\x`, so it is bound as well. The occurrence of `y` is bound; and the occurrence of `z` is free.
-
-To read further:
-
-*      [[!wikipedia Free variables and bound variables]]
-
-Here's an example of beta-reduction:
-
-       ((\x (y x)) z)
-
-beta-reduces to:
-
-       (y z)
-
-We'll write that like this:
-
-       ((\x (y x)) z) ~~> (y z)
-
-Different authors use different notations. Some authors use the term "contraction" for a single reduction step, and reserve the term "reduction" for the reflexive transitive closure of that, that is, for zero or more reduction steps. Informally, it seems easiest to us to say "reduction" for one or more reduction steps. So when we write:
-
-       M ~~> N
-
-We'll mean that you can get from M to N by one or more reduction steps. Hankin uses the symbol <code><big><big>&rarr;</big></big></code> for one-step contraction, and the symbol <code><big><big>&#8608;</big></big></code> for zero-or-more step reduction. Hindley and Seldin use <code><big><big><big>&#8883;</big></big></big><sub>1</sub></code> and <code><big><big><big>&#8883;</big></big></big></code>.
-
-When M and N are such that there's some P that M reduces to by zero or more steps, and that N also reduces to by zero or more steps, then we say that M and N are **beta-convertible**. We'll write that like this:
-
-       M <~~> N
-
-This is what plays the role of equality in the lambda calculus. Hankin uses the symbol `=` for this. So too do Hindley and Seldin. Personally, I keep confusing that with the relation to be described next, so let's use this notation instead. Note that `M <~~> N` doesn't mean that each of `M` and `N` are reducible to each other; that only holds when `M` and `N` are the same expression. (Or, with our convention of only saying "reducible" for one or more reduction steps, it never holds.)
-
-In the metatheory, it's also sometimes useful to talk about formulas that are syntactically equivalent *before any reductions take place*. Hankin uses the symbol <code>&equiv;</code> for this. So too do Hindley and Seldin. We'll use that too, and will avoid using `=` when discussing the metatheory. Instead we'll use `<~~>` as we said above. When we want to introduce a stipulative definition, we'll write it out longhand, as in:
-
->      T is defined to be `(M N)`.
-
-We'll regard the following two expressions:
-
-       (\x (x y))
-
-       (\z (z y))
-
-as syntactically equivalent, since they only involve a typographic change of a bound variable. Read Hankin section 2.3 for discussion of different attitudes one can take about this.
-
-Note that neither of those expressions are identical to:
-
-       (\x (x w))
-
-because here it's a free variable that's been changed. Nor are they identical to:
-
-       (\y (y y))
-
-because here the second occurrence of `y` is no longer free.
-
-There is plenty of discussion of this, and the fine points of how substitution works, in Hankin and in various of the tutorials we've linked to about the lambda calculus. We expect you have a good intuitive understanding of what to do already, though, even if you're not able to articulate it rigorously.
-
-*      [More discussion in week 2 notes](/week2/#index1h1)
-
-
-Shorthand
----------
-
-The grammar we gave for the lambda calculus leads to some verbosity. There are several informal conventions in widespread use, which enable the language to be written more compactly. (If you like, you could instead articulate a formal grammar which incorporates these additional conventions. Instead of showing it to you, we'll leave it as an exercise for those so inclined.)
-
-
-**Parentheses** Outermost parentheses around applications can be dropped. Moreover, applications will associate to the left, so `M N P` will be understood as `((M N) P)`. Finally, you can drop parentheses around abstracts, but not when they're part of an application. So you can abbreviate:
-
-       (\x (x y))
-
-as:
-
-       \x (x y)
-
-but you should include the parentheses in:
-
-       (\x (x y)) z
-
-and:
-
-       z (\x (x y))
-
-
-**Dot notation** Dot means "put a left paren here, and put the right
-paren as far the right as possible without creating unbalanced
-parentheses". So:
-
-       \x (\y (x y))
-
-can be abbreviated as:
-
-       \x (\y. x y)
-
-and that as:
-
-       \x. \y. x y
-
-This:
-
-       \x. \y. (x y) x
-
-abbreviates:
-
-       \x (\y ((x y) x))
-
-This on the other hand:
-
-       (\x. \y. (x y)) x
-
-abbreviates:
-
-       ((\x (\y (x y))) x)
-
-
-**Merging lambdas** An expression of the form `(\x (\y M))`, or equivalently, `(\x. \y. M)`, can be abbreviated as:
-
-       (\x y. M)
-
-Similarly, `(\x (\y (\z M)))` can be abbreviated as:
-
-       (\x y z. M)
-
-
-Lambda terms represent functions
---------------------------------
-
-The untyped lambda calculus is Turing complete: all (recursively computable) functions can be represented by lambda terms. For some lambda terms, it is easy to see what function they represent:
-
->      `(\x x)` represents the identity function: given any argument `M`, this function
-simply returns `M`: `((\x x) M) ~~> M`.
-
->      `(\x (x x))` duplicates its argument:
-`((\x (x x)) M) ~~> (M M)`
-
->      `(\x (\y x))` throws away its second argument:
-`(((\x (\y x)) M) N) ~~> M`
-
-and so on.
-
-It is easy to see that distinct lambda expressions can represent the same
-function, considered as a mapping from input to outputs. Obviously:
-
-       (\x x)
-
-and:
-
-       (\z z)
-
-both represent the same function, the identity function. However, we said above that we would be regarding these expressions as synactically equivalent, so they aren't yet really examples of *distinct* lambda expressions representing a single function. However, all three of these are distinct lambda expressions:
-
-       (\y x. y x) (\z z)
-
-       (\x. (\z z) x)
-
-       (\z z)
-
-yet when applied to any argument M, all of these will always return M. So they have the same extension. It's also true, though you may not yet be in a position to see, that no other function can differentiate between them when they're supplied as an argument to it. However, these expressions are all syntactically distinct.
-
-The first two expressions are *convertible*: in particular the first reduces to the second. So they can be regarded as proof-theoretically equivalent even though they're not syntactically identical. However, the proof theory we've given so far doesn't permit you to reduce the second expression to the third. So these lambda expressions are non-equivalent.
-
-There's an extension of the proof-theory we've presented so far which does permit this further move. And in that extended proof theory, all computable functions with the same extension do turn out to be equivalent (convertible). However, at that point, we still won't be working with the traditional mathematical notion of a function as a set of ordered pairs. One reason is that the latter but not the former permits many uncomputable functions. A second reason is that the latter but not the former prohibits functions from applying to themselves. We discussed this some at the end of Monday's meeting (and further discussion is best pursued in person).
-
-
-
-Booleans and pairs
-==================
-
-Our definition of these is reviewed in [[Assignment1]].
-
-
-It's possible to do the assignment without using a Scheme interpreter, however
-you should take this opportunity to [get Scheme installed on your
-computer](/how_to_get_the_programming_languages_running_on_your_computer), and
-[get started learning Scheme](/learning_scheme). It will help you test out
-proposed answers to the assignment.
-
-
-There's also a (slow, bare-bones, but perfectly adequate) version of Scheme available for online use at <http://tryscheme.sourceforge.net/>.
-
diff --git a/topics/_week2_lambda_calculus_intro.mdwn b/topics/_week2_lambda_calculus_intro.mdwn
new file mode 100644 (file)
index 0000000..7c1e4d0
--- /dev/null
@@ -0,0 +1,251 @@
+Basics of Lambda Calculus
+=========================
+
+We often talk about "*the* Lambda Calculus", as if there were just
+one; but in fact, there are many, many variations.  The one we will
+start with, and that we will explore in some detail, is the "pure"
+Lambda Calculus.  And actually, there are many variations even in the
+pure Lambda Calculus.  But all of the variations share a strong family
+resemblance, so what we learn now will apply to all of them.
+
+The lambda calculus we'll be focusing on for the first part of the
+course has no types. Some prefer to say it does have types, it's just
+that there's only one type, so that every expression is a member of
+that one type.  If you say that, you have to say that functions from
+this type to this type also belong to this type. Which is weird... In
+fact, though, such types are studied, under the name "recursive
+types." More about these later in the seminar.
+
+Here is its syntax:
+
+<blockquote>
+<strong>Variables</strong>: <code>x</code>, <code>y</code>, <code>z</code>...
+</blockquote>
+
+Each variable is an expression. For any expressions M and N and variable a, the following are also expressions:
+
+<blockquote>
+<strong>Abstract</strong>: <code>(&lambda;a M)</code>
+</blockquote>
+
+We'll tend to write <code>(&lambda;a M)</code> as just `(\a M)`, so we don't have to write out the markup code for the <code>&lambda;</code>. You can yourself write <code>(&lambda;a M)</code> or `(\a M)` or `(lambda a M)`.
+
+<blockquote>
+<strong>Application</strong>: <code>(M N)</code>
+</blockquote>
+
+
+Examples of expressions:
+
+       x
+       (y x)
+       (x x)
+       (\x y)
+       (\x x)
+       (\x (\y x))
+       (x (\x x))
+       ((\x (x x)) (\x (x x)))
+
+The lambda calculus has an associated proof theory. For now, we can regard the
+proof theory as having just one rule, called the rule of **beta-reduction** or
+"beta-contraction". Suppose you have some expression of the form:
+
+       ((\a M) N)
+
+that is, an application of an abstract to some other expression. This compound form is called a **redex**, meaning it's a "beta-reducible expression." `(\a M)` is called the **head** of the redex; `N` is called the **argument**, and `M` is called the **body**.
+
+The rule of beta-reduction permits a transition from that expression to the following:
+
+       M [a:=N]
+
+What this means is just `M`, with any *free occurrences* inside `M` of the variable `a` replaced with the term `N`.
+
+What is a free occurrence?
+
+>      An occurrence of a variable `a` is **bound** in T if T has the form `(\a N)`.
+
+>      If T has the form `(M N)`, any occurrences of `a` that are bound in `M` are also bound in T, and so too any occurrences of `a` that are bound in `N`.
+
+>      An occurrence of a variable is **free** if it's not bound.
+
+For instance:
+
+
+>      T is defined to be `(x (\x (\y (x (y z)))))`
+
+The first occurrence of `x` in T is free.  The `\x` we won't regard as containing an occurrence of `x`. The next occurrence of `x` occurs within a form that begins with `\x`, so it is bound as well. The occurrence of `y` is bound; and the occurrence of `z` is free.
+
+To read further:
+
+*      [[!wikipedia Free variables and bound variables]]
+
+Here's an example of beta-reduction:
+
+       ((\x (y x)) z)
+
+beta-reduces to:
+
+       (y z)
+
+We'll write that like this:
+
+       ((\x (y x)) z) ~~> (y z)
+
+Different authors use different notations. Some authors use the term "contraction" for a single reduction step, and reserve the term "reduction" for the reflexive transitive closure of that, that is, for zero or more reduction steps. Informally, it seems easiest to us to say "reduction" for one or more reduction steps. So when we write:
+
+       M ~~> N
+
+We'll mean that you can get from M to N by one or more reduction steps. Hankin uses the symbol <code><big><big>&rarr;</big></big></code> for one-step contraction, and the symbol <code><big><big>&#8608;</big></big></code> for zero-or-more step reduction. Hindley and Seldin use <code><big><big><big>&#8883;</big></big></big><sub>1</sub></code> and <code><big><big><big>&#8883;</big></big></big></code>.
+
+When M and N are such that there's some P that M reduces to by zero or more steps, and that N also reduces to by zero or more steps, then we say that M and N are **beta-convertible**. We'll write that like this:
+
+       M <~~> N
+
+This is what plays the role of equality in the lambda calculus. Hankin uses the symbol `=` for this. So too do Hindley and Seldin. Personally, I keep confusing that with the relation to be described next, so let's use this notation instead. Note that `M <~~> N` doesn't mean that each of `M` and `N` are reducible to each other; that only holds when `M` and `N` are the same expression. (Or, with our convention of only saying "reducible" for one or more reduction steps, it never holds.)
+
+In the metatheory, it's also sometimes useful to talk about formulas that are syntactically equivalent *before any reductions take place*. Hankin uses the symbol <code>&equiv;</code> for this. So too do Hindley and Seldin. We'll use that too, and will avoid using `=` when discussing the metatheory. Instead we'll use `<~~>` as we said above. When we want to introduce a stipulative definition, we'll write it out longhand, as in:
+
+>      T is defined to be `(M N)`.
+
+We'll regard the following two expressions:
+
+       (\x (x y))
+
+       (\z (z y))
+
+as syntactically equivalent, since they only involve a typographic change of a bound variable. Read Hankin section 2.3 for discussion of different attitudes one can take about this.
+
+Note that neither of those expressions are identical to:
+
+       (\x (x w))
+
+because here it's a free variable that's been changed. Nor are they identical to:
+
+       (\y (y y))
+
+because here the second occurrence of `y` is no longer free.
+
+There is plenty of discussion of this, and the fine points of how substitution works, in Hankin and in various of the tutorials we've linked to about the lambda calculus. We expect you have a good intuitive understanding of what to do already, though, even if you're not able to articulate it rigorously.
+
+*      [More discussion in week 2 notes](/week2/#index1h1)
+
+
+Shorthand
+---------
+
+The grammar we gave for the lambda calculus leads to some verbosity. There are several informal conventions in widespread use, which enable the language to be written more compactly. (If you like, you could instead articulate a formal grammar which incorporates these additional conventions. Instead of showing it to you, we'll leave it as an exercise for those so inclined.)
+
+
+**Parentheses** Outermost parentheses around applications can be dropped. Moreover, applications will associate to the left, so `M N P` will be understood as `((M N) P)`. Finally, you can drop parentheses around abstracts, but not when they're part of an application. So you can abbreviate:
+
+       (\x (x y))
+
+as:
+
+       \x (x y)
+
+but you should include the parentheses in:
+
+       (\x (x y)) z
+
+and:
+
+       z (\x (x y))
+
+
+**Dot notation** Dot means "put a left paren here, and put the right
+paren as far the right as possible without creating unbalanced
+parentheses". So:
+
+       \x (\y (x y))
+
+can be abbreviated as:
+
+       \x (\y. x y)
+
+and that as:
+
+       \x. \y. x y
+
+This:
+
+       \x. \y. (x y) x
+
+abbreviates:
+
+       \x (\y ((x y) x))
+
+This on the other hand:
+
+       (\x. \y. (x y)) x
+
+abbreviates:
+
+       ((\x (\y (x y))) x)
+
+
+**Merging lambdas** An expression of the form `(\x (\y M))`, or equivalently, `(\x. \y. M)`, can be abbreviated as:
+
+       (\x y. M)
+
+Similarly, `(\x (\y (\z M)))` can be abbreviated as:
+
+       (\x y z. M)
+
+
+Lambda terms represent functions
+--------------------------------
+
+The untyped lambda calculus is Turing complete: all (recursively computable) functions can be represented by lambda terms. For some lambda terms, it is easy to see what function they represent:
+
+>      `(\x x)` represents the identity function: given any argument `M`, this function
+simply returns `M`: `((\x x) M) ~~> M`.
+
+>      `(\x (x x))` duplicates its argument:
+`((\x (x x)) M) ~~> (M M)`
+
+>      `(\x (\y x))` throws away its second argument:
+`(((\x (\y x)) M) N) ~~> M`
+
+and so on.
+
+It is easy to see that distinct lambda expressions can represent the same
+function, considered as a mapping from input to outputs. Obviously:
+
+       (\x x)
+
+and:
+
+       (\z z)
+
+both represent the same function, the identity function. However, we said above that we would be regarding these expressions as synactically equivalent, so they aren't yet really examples of *distinct* lambda expressions representing a single function. However, all three of these are distinct lambda expressions:
+
+       (\y x. y x) (\z z)
+
+       (\x. (\z z) x)
+
+       (\z z)
+
+yet when applied to any argument M, all of these will always return M. So they have the same extension. It's also true, though you may not yet be in a position to see, that no other function can differentiate between them when they're supplied as an argument to it. However, these expressions are all syntactically distinct.
+
+The first two expressions are *convertible*: in particular the first reduces to the second. So they can be regarded as proof-theoretically equivalent even though they're not syntactically identical. However, the proof theory we've given so far doesn't permit you to reduce the second expression to the third. So these lambda expressions are non-equivalent.
+
+There's an extension of the proof-theory we've presented so far which does permit this further move. And in that extended proof theory, all computable functions with the same extension do turn out to be equivalent (convertible). However, at that point, we still won't be working with the traditional mathematical notion of a function as a set of ordered pairs. One reason is that the latter but not the former permits many uncomputable functions. A second reason is that the latter but not the former prohibits functions from applying to themselves. We discussed this some at the end of Monday's meeting (and further discussion is best pursued in person).
+
+
+
+Booleans and pairs
+==================
+
+Our definition of these is reviewed in [[Assignment1]].
+
+
+It's possible to do the assignment without using a Scheme interpreter, however
+you should take this opportunity to [get Scheme installed on your
+computer](/how_to_get_the_programming_languages_running_on_your_computer), and
+[get started learning Scheme](/learning_scheme). It will help you test out
+proposed answers to the assignment.
+
+
+There's also a (slow, bare-bones, but perfectly adequate) version of Scheme available for online use at <http://tryscheme.sourceforge.net/>.
+
index 9473c33..f47cd85 100644 (file)
@@ -70,6 +70,7 @@ will be just another way to write:
 
 You see that you can use parentheses in the standard way. By the way, `<=` means &le; or "less than or equals to", and `>=` means &ge;. Just in case you haven't seen them written this way before.
 
+<a id=variables></a>
 I've started throwing in some **variables**. We'll say variables are any expression that's written with an initial lower-case letter, then is followed by a sequence of zero or more upper- or lower-case letters, or numerals, or underscores (`_`). Then at the end you can optionally have a `?` or `!` or a sequence of `'`s, understood as "primes." Hence, all of these are legal variables:
 
     x
index 8b6289a..99d8a8b 100644 (file)
@@ -1,5 +1,6 @@
 These are some advanced notes extending the material presented this week. Don't worry about mastering this stuff now if you're already feeling saturated. But you will need to learn these things in the near future, so tackle them as soon as you're ready.
 
+[[!toc]]
 
 ### More on multivalues ###
 
@@ -46,7 +47,7 @@ In OCaml, there are no until-the-end-of-the-line comments. The only comments sta
 
 I agree it's annoying that these conventions are so diverse. There are plenty other commenting conventions out there, too.
 
-
+<a id=funct-declarations></a>
 ### Matching function values ###
 
 A function value doesn't have any structure---at least none that's visible to the pattern-matching system. You can only match against simple patterns like `_` or the variable `f`.
@@ -70,6 +71,7 @@ This is one of the few places where I'll indulge in the use of single `=`. Note
 This special syntax is only permitted in `let`- and `letrec`-constructions, not in `case`-constructions.
 
 
+<a id=guards></a>
 ### Pattern guards ###
 
 In `case` contructions, it's sometimes useful to check not only whether a certain pattern matches, but also whether a certain boolean expression is true, typically where we want some variables in that expression to be bound by the relevant pattern. Thus, for example, if we wanted to count the number of odd numbers in a sequence, we could do this:
@@ -97,6 +99,7 @@ It's a bit cumbersome, though, to have the doubly-embedded `case`-constructions.
 If we get to the `y & ys` line in the pattern list, and the pattern-match succeeds, then we check the guard expression `odd? y`, with `y` bound to whatever part of `xs` matched the corresponding part of the pattern `y & ys`. If that boolean expression is `'true`, then we continue to the right-hand side, after the `then`, just as usual. But if the boolean expression is `'false`, then we treat the whole line as a failed match, and proceed on to the next line in the binding list, if any.
 
 
+<a id=as-patterns></a>
 ### As-patterns ###
 
 Sometimes it's useful to bind variables against overlapping parts of a structure. For instance, suppose I'm writing a pattern that is to be matched against multivalues like `([10, 20], 'true)`. And suppose I want to end up with `ys` bound to `[10, 20]`, `x` bound to `10`, and `xs` bound to `[20]`. Using the techniques introduced so far, I have two options. First, I could bind `ys` against `[10, 20]`, and then initiate a second pattern-match to break that up into `10` and `[20]`. Like this:
@@ -176,6 +179,7 @@ These functions can be defined like this:
     in (fst, snd, swap, dup)
 
 
+<a id=sections></a>
 ### Sections ###
 
 OCaml and Haskell have a convenient bit of syntax for the common case where you want a function like this: