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 -~----------~----~----~----~------~----~------~--~---