On Wed, May 25, 2011 at 10:15 PM, iamcreasy <quazir...@gmail.com> wrote: > 1st question, > Is the form word is a typo here? Isn't the word will be item? If not, > is def a form? That means, this code contains 3 forms. :-s
Technically, anything that can be evaluated is a form. A composite form is something like a literal list, vector, set, or map. The literal list case is treated as an operator and arguments; the other three just evaluate to vectors, sets, or maps, respectively, whose members are the evaluations of the nested forms, so: + => the + function (+ 1 2) => 3 [+ 1 2] => a vector of the + function, 1, and 2. [(+ 1 2)] => [3] #{(+ 1 2) 4} => #{3 4} {:a (+ 1 2)} => {:a 3} > 2nd question, > Is a composite form is a special form only when, the first item of a > list is something that is only predefined withing Clojure? If yes, > then is it possible to create custom special form? Sort of. You can create a macro with defmacro, which like a special form controls the evaluation of its arguments instead of the arguments being evaluated first and the function only getting the results. Things like -> and defn are macros: (-> 3 (+ 1) (* 2)) adds 1 to 3, then doubles, yielding 8. This couldn't work with a function, as it would get arguments 3, 1, and 2 as (+ 1) would evaluate, first, to 1, and (* 2) to 2. It wouldn't know what to do with 3, 1, or 2 -- whether to add 1 and then multiply by 2, or subtract 1 and then add 2, or what. The macro, however, operates on the *forms* and gets 3, (+ 1), and (* 2) and combines the first two into (+ 3 1) and that and the third into (* (+ 3 1) 2) by inserting each form into the next one after the operator and before everything else. (defn foo [a b] (+ (* a a) (* b b))) also cannot be a normal function call. If it were there would be several errors: foo undefined (most likely), also a and b undefined, so the first argument foo could not be evaluated, nor could the second [a b], nor could the third (+ (* a a) (* b b)). But instead it works to generate a function definition. It's a macro that expands to a (def ...) form, in fact. > But, at the beginning the writer said, there are four basic varieties > of forms. > > 1. Literal, > 2. Symbol, > 3. Composite form and > 4. Special form. I'd say it's a bit more complicated than that. We have six things that are evaluated somewhat differently: 1. nil, true, false, numbers, strings, regexps, keywords ... evaluate to themselves. 2. symbols are looked up when evaluated to find a local or global var value they evaluate to. 3. Set, vector, and map literals have subforms evaluated, then evaluate to a set, vector, or map with the subforms replaced by their evaluated values. 4. (foo bar baz), if foo is a special operator like def, is a special form and is evaluated according to the built-in rules for that form. 5. (foo bar baz) with foo not a special operator: the subform foo is looked up at compile time and if it's a macro, macro expansion is performed. The transformed code is then evaluated per these rules. 6. (foo bar baz) with foo not a special operator or a macro. At compile time, code is generated to evaluate foo, bar, and baz at runtime and then apply foo as a function to the arguments bar and baz. The latter three can, of course, have zero or more arguments, not just two, and generalize appropriately. Different things happen at compile and run time in each case: Thing Compile Run literal inserted into bytecode recalled from memory symbol var resolved, deref compiled var is deref'd (def bar baz) bar var interned baz eval'd, bar set (macro x y) macro is expanded expansion is eval'd (func bar baz) fn-calling code compiled func called with args For special forms other than def, the behavior varies; (if bar baz quux) for example compiles to a conditional test and branch and at run time bar is eval'd, then the test and possibly the branch occurs, and either baz or quux is eval'd. > According to the definition of Symbols from the book, its not a > symbol. 'def is definitely a symbol. (No pun intended.) However (def ...) is recognized as a special form by the compiler. Note that: def symbol (def ...) special form You can actually create variables named def and the like. If you reference them in other than operator position, it works: => (defn def [x] (+ x 2)) #'user/def => (map def [1 2 3 4 5]) (3 4 5 6 7) In operator position, though, you get the special form unless you qualify the name: => (def quux 42) #'user/quux => (user/def quux) 44 If you define it locally, you can't use it in operator position at all, unless you rename it: => (let [def (fn [x y] (+ x y 2)) a def] (println (def foo 42)) (println (a foo 42))) #'user/foo 86 nil The second let binding gives the local def another name, a, that can be used to invoke it. It ends up using the foo that was def'd the line before as one of its arguments. The same thing can be used if a function argument or a loop binding is named def, and for any other special operator's name besides def. But although it can be done it is generally best to avoid naming any variable with the name of a special form, and especially any function, or anything you might want to call like a function, such as a map or a keyword. You also can't use 'nil, 'true, or 'false as names this way, or at all easily. The reader turns "nil", "true", and "false" into literal nil, true, and false objects, not symbols: => (def nil 42) #<CompilerException java.lang.Exception: First argument to def must be a Symbol (NO_SOURCE_FILE:1)> You can work around that by using eval when you need the name unqualified, but please just pick some other name instead: => (eval `(def ~(symbol "nil") 42)) #'user/nil You can use it qualified without difficulty: => user/nil 42 -- Protege: What is this seething mass of parentheses?! Master: Your father's Lisp REPL. This is the language of a true hacker. Not as clumsy or random as C++; a language for a more civilized age. -- 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 Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en