From: jim
Date: Wed, 18 Feb 2015 16:22:00 +0000 (-0500)
Subject: update
X-Git-Url: http://lambda.jimpryor.net/git/gitweb.cgi?p=lambda.git;a=commitdiff_plain;h=904a85dae5a66e8198ebd3626f4044e590595a9f
update
---
diff --git a/topics/week3_unit.mdwn b/topics/week3_unit.mdwn
index f3f61b4c..c0b26090 100644
--- a/topics/week3_unit.mdwn
+++ b/topics/week3_unit.mdwn
@@ -1,4 +1,4 @@
-[[!TOC]]
+[[!toc]]
What is *unit*?
===============
@@ -11,12 +11,12 @@ In the other notes, we discussed how to encode such data structures in the Lambd
The component `Cyan ()` says here is one variant, that we will associate with the *tag* `Cyan`, and this variant has no parameters. Here we write that as `()`, for better consistency with the final case where the variant has multiple parameters, but different notational conventions, such as omitting the `()`, would also be possible. The final component `Gray (Number, Number)` says the last variant is associated with the tag `Gray`, and also specifies that this variant has two parameters, and that we expect each of them to be a number. The vertical bar `|` is just a syntactic separator, like a comma.
-These "tags" are also called **constructors**, or more specifically "data constructors". (Later we will encounter other kinds of constructors. But "constructor" without any modifiers or special context can be assumed to mean these things.) The reason they are called that is that the way to specify some *instance* of this data structure is to write things like:
+These "tags" are also called **constructors**, or more specifically "data constructors". (Later we will encounter other kinds of constructors. But "constructor" without any modifiers or special context can be assumed to mean these things.) The reason they are called that is that the way to specify *some instance* of this data structure is to write:
Cyan ()
Gray (5, 0)
-These may look like function applications, but they're not. They're canonical "constructions" of those instances of the data structure. Notice that in the `Gray` case, we construct an instance using specific numbers; whereas in the description of the data structure itself, we used not specific numbers but instead the general type `Number`.
+These may look like function applications, but they're not. They're canonical *constructions* of those instances of the data structure. Notice that in the `Gray` case, we construct an instance using specific numbers; whereas in the description of the data structure itself, we used not specific numbers but instead the general type `Number`.
(Here too other conventions would be possible, such as, again, omitting the `()` after the `Cyan`. Here we also follow the general convention of Haskell and OCaml in capitalizing the alphabetic names of constructors; whereas, on the other hand, variables bound to functions begin with lowercase letters. In fact, in both languages there are also some constructors written outside this convention. Our friends that we express in Kapulet as `[]` and `&` can be thought of as constructors, too. Haskell expresses those as `[]` and `:` and OCaml as `[]` and `::`. Also, as we said in the other notes, we might think of the *boolean truth-values* as variants in a data structure. Following the conventions here, the most consistent nomenclature would then be to designate them `True ()` and `False ()`. Haskell sort-of does that, but omits the `()`. OCaml also omits the `()` and in this unique case expresses the variants all lower-case rather than capitalized.)
@@ -86,7 +86,7 @@ and those would mean the same as:
Quadruple (5, 0, 'false, 12)
-Similarly, `Quadruple (5, 0, 'false, (), 12)` would also mean the same; though again you may not be able to imagine cases where it's useful to write it in that longer form. On the other hand, you could not say `Quadruple (5, 0, 'false, Unit (), 12)`, because that would be trying to construct a quadruple out of *five* values.
+Similarly, `Quadruple (5, 0, 'false, (), 12)` would also mean the same; though again you may not be able to imagine cases where it's useful to write it in that longer form. On the other hand, you could not say `Quadruple (5, 0, 'false, Unit (), 12)`, because that would be trying to construct a *quad*ruple out of *five* values.
As I said, there is some conceptual benefit to having both the heavyweight and the lightweight notion of a triple, and the notions of `Unit ()` versus `()` are the corresponding, limiting cases of these. Our discussion below of the ways in which *unit* could be useful really applies to *both* of Kapulet's `Unit ()` and Kapulet's `()`. It's just that which of these notions you focus on will affect how you conceptualize what's going on. If I say:
@@ -225,7 +225,7 @@ We asked before how you specify an imp. We've seen one notation, using an initia
returns the imp whose first member is the symbol `'-` (if you left the quote off, you would instead get the function that this symbol is bound to), whose second member is the number 3, whose third value is whatever value the symbol/variable `y` is bound to, and whose final value is the empty list.
-What if you want to instead build an *improper* imp, such as `(5 0 . y)`, again using the value `y` is bound to rather than the quoted symbol? There is no form in *standard* Scheme to do this *directly*. But many Scheme *implementations* do have a special function for it. Racket calls it `list*`, so if you write in Racket:
+What if you want to instead build an *improper* imp, such as `(5 0 . y)`, again using the value `y` is bound to rather than the quoted symbol? There is no function in *standard* Scheme to do this *directly*. But many Scheme *implementations* do have a special function for it. Racket calls it `list*`, so if you write in Racket:
(let* ((y #f))
(list* 5 0 y))
@@ -244,7 +244,7 @@ Okay, all of that was just us getting clear about Scheme's *longer* containers,
Scheme does have vectors of length one: you can write `(vector 5)` or `#(5)`. And that will be distinct from the number `5`. Kapulet is similar: we could have a heavyweight one-tuple, perhaps `Single 5` (or `Single (5)`, the parentheses make no difference when they contain exactly one syntactic atom), that would be distinct from the number `5`. But there is no difference among lightweight tuples. In Kapulet, `(5)` and `5` would just be notational variants for the number. Although OCaml and Haskell for the most part have tuples corresponding to Kapulet's heavyweight tuples, in this case they do not. Some subtleties about their type systems aside, they don't have any native one-tuple `(5)` that's distinct from mere `5`.
-Scheme doesn't have any *imps* of length one, because it builds its imps out of dotted pairs, so they can't get any smaller than length two.
+Scheme doesn't have any *imps* of length one, because it builds its imps out of dotted pairs, so they can't get any smaller than length two. (Some Schemes do have a separate notion of a *box*, which is isomorphic to vectors of length one.)
Now how about unit(s)? Here again, Scheme has vectors of that length: you can write `(vector)` or `#()`. And that will in many ways correspond to the heavyweight Kapulet length-zero tuple `Unit ()`. Here too, there can be no imps that are this short.
@@ -261,14 +261,14 @@ your Scheme interpreter will probably just not show any result, not even a blank
(display x)
-it might have said `#` or `#`.
+it might have shown `#` or `#`.
Even if your Scheme implementation lacks the `void` function, though --- as the official standard permits it to do --- you can still generate the special *void* value in other ways. One example is if a `cond` expression has no `else` clause, but none of the clauses that *are* supplied succeed. So this will also generate the special *void* value:
(cond
(#f 'impossible))
-Ok. Let's pull this all together. Scheme has two heavyweight values corresponding to Kapulet's `Unit ()`, namely its length-one vector (expressible as `(vector)` or `#()`) and its special *void* value (expressible in various ways). It has two heavyweight values corresponding to Kapulet's `Triple (0, 5, #f)`, namely a length-three vector and a length-three imp. Corresponding to the *lightweight* Kapulet tuples or multi-values are the Scheme idioms:
+Ok. Let's pull this all together. Scheme has two heavyweight values corresponding to Kapulet's `Unit ()`, namely its length-zero vector (expressible as `(vector)` or `#()`) and its special *void* value (expressible in various ways). It has two heavyweight values corresponding to Kapulet's `Triple (0, 5, #f)`, namely a length-three vector and a length-three imp. Corresponding to the *lightweight* Kapulet tuples or multi-values are the Scheme idioms:
; when calling Scheme functions
(f 0 5 #f)
@@ -290,7 +290,7 @@ As I mentioned in class, you might sometimes want to use *unit* as a parameter t
If the notion so expressed is important enough, we might give it its *own*, dedicated data structure, that just left out the head parameter. Informationally, it's all the same whether you omit some parameter or include it but offer only one choice for what it can be. Indeed I suggested that this is a helpful way to think of Numbers as compared to Lists.
-But sometimes the more general data structure you're working with will be well-developed, and have lots of code already built up around it, prepared to handle parameters of many types. And the special case where you don't care about the identity of the parameter might be more limited purpose, that's easier to just piggy-back on the more general notion than to write separate code for. In these cases *units* can be a useful choice for the type of some parameter, precisely because they are uninformative.
+But sometimes the more general data structure you're working with will be well-developed, and have lots of code already built up around it, prepared to handle parameters of many types. And the special case where you don't care about the identity of the parameter might be more limited purpose, that's easier to just piggy-back on the more general notion than to write separate code for. In these cases *Units* can be a useful choice for the type of some parameter, precisely because they are uninformative.
(For these purposes you'd want to use heavyweight units, like Kapulet's `Unit ()` or Haskell and OCaml's `()`. For the remaining jobs to be discussed below, however, arguably *either* of Kapulet's heavyweight or lightweight units could be deployed.)