I only read Section 1.4. In general, I think it’s well-done (besides the parts that are obviously unfinished.) I like the clear and simple language, although it sometimes degenerates into excessive handwaviness, as I’ll elaborate.
Page numbers are what my PDF reader tells me. (Adding page numbers to the document itself might help reviewers.)
Section 1.4.1:
p. 52:
“While a Turing machine…” – This sentence is strangely non-parallel. I suggest contrasting Turing-machine-as-hardware with lambda-calculus-as-software.
“The most famous of these are Haskell and Lisp” – uh, I say this a Haskell guy, but the ML family of languages is just as famous as Haskell if not more so.
“So, everyone majoring in computer science at MIT…” – see http://www-tech.mit.edu/V125/N65/coursevi.html – you might want to fact-check this before the book goes out.
“In imperative programming, a program…” – this sentence is vague, and so is the rest of the paragraph. In particular, “how to change state” hides the real difference between imperative languages and functional languages. Languages in both paradigms let you write programs that manipulate state. The distinction is as to whether the state is *explicit* or not. If I were writing this I’d explain that the imperative paradigm concerns more operational, or procedural approaches to describing algorithms, and the functional paradigm emphasizes more mathematical, or declarative approaches.
Same para: “Functional programming is seemingly more limited…” – watch out when you use weasel words like “seemingly”. Whether functional programming seems more limited depends on your perspective. It may seem more limited to C programmers. But other people aren’t necessarily coming at it with that bias. It’s also odd and misleading to describe functional languages’ lack of implicit state as a “limitation”, since as you well know, languages with or without implicit state are equally computationally powerful.
There’s some confusion and vagueness in this section as to whether by “functional languages” you mean “purely functional languages”, which you surely do. An impure functional language (and some people say “if it isn’t pure, it isn’t functional”) like Lisp doesn’t have the nice theoretical properties you want. The only widely used programming language that does is Haskell 98 (not that anyone really programs in Haskell 98, but with the language extensions that most people do use, Haskell isn’t pure either…)
“In fact, the best-behaved functional programming languages…” – “best-behaved” is quite a subjective term. Programmers may well think that a strongly normalizing language (such as the simply-typed lambda-calculus) is *not* well-behaved – most programmers like being able to write nonterminating programs! I think this entire paragraph needs a lot of work. “Input into itself”, for example, is handwavy. You’re eliding a lot of subtlety here. At least to me, when I was learning this subject, the connection between types and the ability/lack thereof to write nonterminating programs was far from obvious.
“…the typed lambda calculus is just another way of talking about cartesian closed categories”: “Just another way” is rather dismissive. I suggest saying “Lambek found a way to interpret the typed lambda-calculus in terms of cartesian closed categories,” or something like that, that doesn’t imply that cartesian closed categories are the more privileged theoretical concept. Along the same lines, I think your assertion that “theoretical computer science has been closely entwined with category theory” is controversial. Certainly there has been a lot of work on the connections between CT and theoretical CS, but not all theoretical computer scientists think that CT is central to their work. It might be good to get more opinions on this.
“Combinatory logic is closely related to the lambda calculus…” – this is vague. Either explain that the two formalisms are related as being alternative minimalist Turing-complete computational systems (I don’t see what other relationship you might mean), or don’t say it at all.
p. 53
“Strips everything down to the bare minimum” is vague. Emphasize that combinatory logic is different because it avoids naming and the complicated machinery (substitution) associated with it – that would be easier to understand. “…In some ways more awkward…” – Again, this is weaselly. Some people think lambda calculus is more awkward because you need to worry about substitution. Don’t state opinions as facts.
“…it seems more efficient…” – Be bold and don’t say what “seeems” to be more efficient, say what you think *is* more efficient.
Section 1.4.2 (still on p. 53)
1st para: Rewrite to be parallel: “Mathematicians might apply… Functional programmers apply…” (Then you get the added bonus of active voice.)
“…suppose we have programs…” “…compute the obvious functions…” – I think you’re using “program” and “function” interchangeably. Use a consistent lexical set, or if you do mean something different, explain the difference between “program” and “function”.
You introduce equational reasoning here in a very vague way. Not all readers may be used to this style of writing programs.
p. 54
“To avoid problems…” – super-vague. Say *what* problems a non-confluent rewrite system causes. Or just declare that we want to talk about confluent rewrite systems, without justifying it.
Your definition of “confluence” is wrong or at least very misleading: when you say “back to the same expression”, I think you’re trying to say that when there’s a choice of rules to apply, you’ll still get the same normal form in the end, either way. But the resulting normal form is not the original expression, which “back to the same expression” implies. This whole paragraph is pretty handwavy.
I suggest putting in a citation for those who want further reading on rewrite systems: Baader and Nipkow’s _Term Rewriting and All That_ is a good one.
“We can handle…” Avoid noise words like “using”. “‘Currying’ is a trick that helps us handle functions…” In the next sentence, what’s “this”? Well, currying doesn’t turn a function of several arguments into anything – currying lets us *define* a function of several arguments as a function that (blah blah). So say that.
“…we can imagine a program plus that adds integers” – this paragraph seems to end a bit abruptly.
“…that branch to the left:” – I find that sentence unnecessary; you can just look at the picture.
p. 55
“…has no well-defined meaning.” – it’s nonsensical to talk about whether a program has a well-defined meaning unless you’ve defined the semantics for the language in which you’re programming. I would say this differently. It’s possible to define a very sensible language in which “(double Tuesday)” has a meaning, after all. Instead I would pick an example of an ill-typed program that’s actually *inconsistent*: for example, one that uses the same value in an integer context and a string context. Now, this could have a perfectly good meaning as well (say, in Tcl), but then you can point out that in most sensible languages it would be ill-typed because strings and integers have different machine representations.
“…instantly complain…” – it’s unclear what “instantly” means. Instead, I would emphasize the compile-time/run-time distinction.
It would be nice to give a nod to type inference in this section, so readers aren’t left with the impression that you always have to write explicit types in a functional language.
“in a variety of ways” – delete that phrase; the sentence has equivalent meaning without it.
“…there is a new type…” – the use of “new” is strange; a function type is no newer than its components. “another type”, perhaps?
“Any program is built…” – this sentence is extremely confusion. Rewrite it, preferably as two or three separate sentences.
“…a datum of type X…” – so f is like a constant function. Say that, perhaps.
p. 56
“…can be reinterpreted as…” – because you use the passive voice, I am confused by what you mean. Who does the reinterpreting? Saying it would clarify the idea.
“In functional programming, we take advantage…” – I have no idea what you’re trying to get at with this sentence.
“Computer scientists call…” – again, the “new”/”old” language is confusing. How about “building more complicated types from simpler types”?
“…a less awkward way…” – Again, don’t make unsubstantiated assertions. Whether currying is more awkward than tupling is a matter of taste.
Skipping to p. 58:
The void type (or unit type – which might be less confusing than “void type”, since the “void” type in C has a very different semantics than the unit type in Haskell or ML, and I think you really mean the latter) is useful in purely functional languages, too, not just in languages with side effects. See Pierce’s _Types and Programming Languages_. Also, “languages with side-effects” is a strange thing to say, because all programming languages allow you to write programs that have side effects. But a purely functional language provides a type system that controls and encapsulates effects. I would distinguish between pure/impure languages rather than languages with/without side effects.
Re: Computer Scientists Needed Now
A really minor comment: the definition of currying on page 57 gives the type as
whilst virtually all the references on the web use the form
curry : ((a,b) -> c) -> (a -> b -> c)
(keeping it in the original notation CS people will be used to)
eg, see http://en.wikipedia.org/wiki/Currying http://www.cs.nott.ac.uk/~gmh/faq.html#currying
so you might want to explain why you’ve chosen an opposite definition. (In fact, you seem to have the opposite convention on pages 58-59 in calculi rules.) Also, you motivate product types with “This gives a less awkward way to deal with programs that take more than one argument.” I’d say you probably need to go deeper and say that product types make it easier for “functions” to output intermediate data structures so you can write programs piece by piece (as there’s no obvious “lack of ease” in having more than one argument in the curried style in the examples you’ve presented in the paper).