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

Reply via email to