Hi Brian,

Looks really good.

> My intro is meant as a
> sequential tour through the essential concepts, not a practical
> tutorial. In particular, my examples are deliberately cursory and
> abstract, and my API coverage is very minimal.

I have some comments which may go beyond your desired scope, but I
don't think would bloat it:

1) "Learning Clojure" launches straight into describing Clojure. I
think you should at least have a link to a more basic tutorial or
dedicate a paragraph to the syntax so that your concepts can be more
fully understood.
- I propose you should have a link to 
http://en.wikibooks.org/wiki/Clojure_Programming/Getting_Started
as a start reference
- followed by a paragraph on basic forms (I couldn't find a simple one
to link to a description so I suggest one below)
"Clojure programs are written in forms. Forms enclosed in parenthesis
indicate function calls. eg: (+ 1 2 3) calls the '+' function with
arguments 1 2 3 and returns 6, the sum of its arguments. New functions
can be defined like so: (defn average [x y] (/ (+ x y) 2))   here x
and y are symbols representing the input arguments. '/' is called to
divide the sum of x and y by 2. Note that forms are always in prefix
notation, ie: the operator is called with subsequent arguments. Now
average can be invoked as (average 3 5) and will return 4. <link to
more fully detailed description of forms for later reference>"

2) The functional programming section describes well the differences,
but for someone unfamiliar with FP terminology it can sound like just
a bunch of words. I think some examples really help make the concepts
concrete
"functions without side-effects"
imperative:   void moveplayer( p, x, y ) // updates a player object
with a new location
OO: class player { void move( x, y ) }  // again, mutates an existing
object
FP:  freshp = moveplayer( oldp, x, y )   // a completely new player
has been created, the old player is unaffected
In imperative you only know that p has changed because the function
name hints it. In FP oldp is preserved (you don't need to worry about
what happened to it - nothing can happen to it) and it is explicit
that freshp is a result of moving.

"immutable data"
Consider removing an item from a list:
imperative solution would modify the list in place.
FP solution would return a completely new list, leaving the original
in place.
This sounds on the surface to be wasteful, but there are many ways
that this is optimized by the compiler to be very efficient.
You can immediately see that the FP solution can be used in parallel,
while the imperative cannot.

"first-class functions"
(map + [1 2 3] [4 5 6]) returns (5 7 9). Using functions as arguments
to other functions is very powerful.

"function-based control flow"
You already provide an example with if, which is probably enough. You
might want to give an explicit example though:
(if true (+ 1 2)) returns 3


3) Functions section I would say should go before data types, seeing
it is so central a concept. You mention arity, again I think a short
example would help:
(defn myfun [a & rest] (+ a (apply + rest)))
(myfun 1 2 3 4) returns 10
; The ampersand indicates that the next symbol will take all remaining
arguments into a vector


I noticed in your latter sections you have more examples, which is
great.

I really like that you have a de-structuring section! This is one of
the really powerful features that seems to be completely undocumented
on the website and wiki (that is to say I can't find it, it may
exist). I think this section would be great on the official page also.





Regards,
Tim.
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to