"special form" vs. "macro"

286 views
Skip to first unread message

alux

unread,
May 31, 2010, 3:35:18 AM5/31/10
to Clojure
Hi,

I got a very basic question about the concept of "special form". What
is correct, multiple selections allowed:

[ ] A special form is what can be implemented by a macro.

[ ] Every macro gives a special form.

[ ] Only a macro that doesn't evaluate some of its arguments gives a
special form.

[ ] A special form is always built in, and cannot be implemented in
the language itself.

[ ] Special forms are exactly the things that can be called, but dont
evaluate all of their arguments. (Macros and build-ins, at least for
eager languages.)

[ ] The concept of special form doesnt have anything to do with
eagerness or lazyness.

[ ] You are completely wrong, the right question is:
____________________________

Thank you, alux

Konrad Hinsen

unread,
May 31, 2010, 4:38:13 AM5/31/10
to clo...@googlegroups.com
On 31 May 2010, at 09:35, alux wrote:

> I got a very basic question about the concept of "special form". What
> is correct, multiple selections allowed:
>
> [ ] A special form is what can be implemented by a macro.

Wrong. You cannot implement a Lisp-like language with just macros and
functions. At some point the operations defined by macros and
functions must be reduced to fundamental operations that are handled
directly by the compiler.

Example: if and cond. You can implement either one in terms of the
other one as a macro, but you cannot implement *both* as macros.

> [ ] Every macro gives a special form.

Wrong. A macro rewrites a form to another form. A special form is
interpreted directly by the compiler.

There is also a technical difference: a macro is the value of a name,
which is looked up in the context of the macro call. Constructs like
macrolet (clojure.contrib.macro-utils) permit local macro definitions,
for example. A special form is named by a symbol whose interpretation
cannot be overridden in any way.

> [ ] Only a macro that doesn't evaluate some of its arguments gives a
> special form.

Wrong as well. The distinction between macros and special forms is a
matter of implementation, not of evaluating arguments.

> [ ] A special form is always built in, and cannot be implemented in
> the language itself.

True for a minimalist language implementation. An implementation may
choose to use more special forms than strictly necessary for
performance reasons.

> [ ] The concept of special form doesnt have anything to do with
> eagerness or lazyness.

True.

Konrad.

Jarkko Oranen

unread,
May 31, 2010, 4:48:46 AM5/31/10
to Clojure
On May 31, 10:35 am, alux <alu...@googlemail.com> wrote:

> [  ] A special form is what can be implemented by a macro.

That depends. My understanding is that a special form is something
that is "fundamental" to the language, that the evaluator handles as a
special case. That is, they need to be implemented in the compiler/
interpreter itself. However, in practice you can't really tell the
difference between a macro and a special form, and in fact some
Clojure "special forms" are implemented as macros (on top of a "real"
special form that is an implementation detail)

>
> [  ] Every macro gives a special form.

Not really. All macros have the same evaluation semantics (macro
expansion).

> [  ] Only a macro that doesn't evaluate some of its arguments gives a
> special form.

I don't think evaluation of arguments matters.

>
> [  ] A special form is always built in, and cannot be implemented in
> the language itself.

That depends on your point of view, but in general, yes.

>
> [  ] Special forms are exactly the things that can be called, but dont
> evaluate all of their arguments. (Macros and build-ins, at least for
> eager languages.)

Special forms are special because the evaluator has separate
evaluation rules for each of them. Other than that, they are merely
another kind of operator (the others being macros and functions)

>
> [  ] The concept of special form doesnt have anything to do with
> eagerness or lazyness.

This is correct.

alux

unread,
May 31, 2010, 5:08:29 AM5/31/10
to Clojure
Hello Konrad, many thanks, that clarifies it!

So, in "A special form is always built in, and cannot be implemented
in the language itself." the first part is true, the second is not.
Like most lisps have a bilt in list-reverse for speed reasons.
In that case, this build in thing is a special form that can also be
implemented in the language (only slow).
Right?


"A special form is named by a symbol whose interpretation
cannot be overridden in any way."

This explains the problem from another thread (that made me ask this
question in the first place):

user=> (def do println)
#'user/do

; this uses the special form
user=> (do "huhu" "plop")
"plop"

; while this uses println
user=> ((var do) "huhu" "hello")
huhu hello
nil


Thank you, alux

Konrad Hinsen

unread,
May 31, 2010, 5:43:00 AM5/31/10
to clo...@googlegroups.com
On 31 May 2010, at 11:08, alux wrote:

> Hello Konrad, many thanks, that clarifies it!
>
> So, in "A special form is always built in, and cannot be implemented
> in the language itself." the first part is true, the second is not.
> Like most lisps have a bilt in list-reverse for speed reasons.
> In that case, this build in thing is a special form that can also be
> implemented in the language (only slow).
> Right?

Right.

> "A special form is named by a symbol whose interpretation
> cannot be overridden in any way."
>
> This explains the problem from another thread (that made me ask this
> question in the first place):
>
> user=> (def do println)
> #'user/do
>
> ; this uses the special form
> user=> (do "huhu" "plop")
> "plop"
>
> ; while this uses println
> user=> ((var do) "huhu" "hello")
> huhu hello
> nil

Yes, that illustrates the handling of special forms nicely. Note that
it is somewhat specific to Clojure. Other Lisps handle the mapping
from symbols to functions/macros/special forms differently.

One more variant is helpful:

user=> (user/do "huhu" "hello")
huhu hello
nil

This illustrates that special forms need to be identified by an
unqualified symbol in the operator position.

Another detail that is good to know is that syntax-quote (`) knows
about special forms and treats their symbols specially even if they
are not in the operator position:

user=> (declare do foo)
#'user/foo
user=> `do
do
user=> `foo
user/foo

Konrad.

Sina K. Heshmati

unread,
May 31, 2010, 6:45:34 AM5/31/10
to clo...@googlegroups.com
"alux" <alu...@googlemail.com> said:

> I got a very basic question about the concept of "special form". What
> is correct, multiple selections allowed:
>
> [ ] A special form is what can be implemented by a macro.

Wrong. Macros cannot remove the need for special-forms, at least not in a real interpreter. In a metacircular implementation, you can replace special-forms with calls to the base-level implementation. For instance, if you evaluate 'if' at base-level, then you can use it to define 'cond' at base-level.

> [ ] Every macro gives a special form.

They can all be reduced to a number of expressions that cannot be implemented by neither macros nor functions.

These expressions can be evaluated using normal functions if you have lazy evaluation of arguments. So, if you have lazy-eval, there's no need for special-forms.

> [ ] Only a macro that doesn't evaluate some of its arguments gives a
> special form.

You could say that.

> [ ] A special form is always built in, and cannot be implemented in
> the language itself.

Unless you have lazy-eval.

> [ ] Special forms are exactly the things that can be called, but dont
> evaluate all of their arguments. (Macros and build-ins, at least for
> eager languages.)
>

> [ ] The concept of special form doesnt have anything to do with
> eagerness or lazyness.

Wrong. It has everything to do with laziness. If you have one, you don't need the other.

Please note that, the concept of special-forms is a compromise and I don't think anyone would want to have them. A language designer has to make a choice as to whether to have special forms or not. If they don't want special-forms, then they should provide lazy evaluation of arguments.

Some introduce functional parameters in order to provide lazy evaluation of arguments but that choice has its own trade-offs since it introduces a kind of dynamic scoping.

Kind regards,
SinDoc

Sina K. Heshmati

unread,
May 31, 2010, 6:50:00 AM5/31/10
to clo...@googlegroups.com
"Sina K. Heshmati" <si...@khakbaz.com> said:
> "alux" <alu...@googlemail.com> said:
>
>> I got a very basic question about the concept of "special form". What
>> is correct, multiple selections allowed:
>>
>> [ ] A special form is what can be implemented by a macro.
>
> Wrong. Macros cannot remove the need for special-forms, at least not in a real
> interpreter. In a metacircular implementation, you can replace special-forms with
> calls to the base-level implementation. For instance, if you evaluate 'if' at
> base-level, then you can use it to define 'cond' at base-level.

Oh, I meant:
... then you can use it to define 'cond' at *meta*-level.

Patrick Stein

unread,
May 31, 2010, 10:06:17 AM5/31/10
to Clojure
Maybe Clojure uses the term "special form" differently than Common
Lisp does, but here's how to think of "special form" in the Common
Lisp sense.

A form that is *NOT* a special form like (F A B C D ...) will either
evaluate:

1. (SYMBOL-FUNCTION F), then A, B, C, D, ... in order from left-to-
right, OR
2. A, B, C, D, ... in order from left-to-right then (SYMBOL-FUNCTION
F)

And, cannot change the lexical environment (add or remove symbols in
the environment).

It is up to the implementation whether (SYMBOL-FUNCTION F) gets
evaluated first or last, but A, B, C, D, ... get evaluated from let to
right in order before F is invoked.

Any form that does not ALWAYS obey that is a "special form".

Examples:

(+ 3 5 (+ 6 7) ii), the form 3 is evaluated, then 5, then (+ 6 7),
then ii, then all of these are passed to (SYMBOL-FUNCTION +) to
execute. This IS NOT a special form.

(IF A B C) does not evaluate both B and C. Thus, it IS a special
form.

The following IS NOT a special form (as long as XX and YY aren't
dynamic variables that we're overriding but rather just local
variables here like it looks) because it always evaluates A and B in
the expected order:
(DEFMACRO WEIRD (A B)
`(LET ((XX ,A))
(LET ((YY ,B))
(DO-SOMETHING (+ XX YY) (- XX YY)))))

(WEIRD (+ 6 7) ii)


The following IS a special form because it does not evaluate A and B
in the expected order:
(DEFMACRO WEIRD-SPECIAL (A B)
`(LET ((YY ,B))
(LET ((XX ,A))
(DO-SOMETHING (+ XX YY) (- XX YY)))))

(WEIRD-SPECIAL (+ 6 7) ii)

The following IS also a special form since it doesn't always evaluate
A and B in the expected order:
(DEFMACRO WEIRD-MAY-BE-SPECIAL (SPECIAL A B)
`(IF ,SPECIAL
(LET ((XX ,A))
(LET ((YY ,B))
(DO-SOMETHING (+ XX YY) (- XX YY))))
(LET ((YY ,B))
(LET ((XX ,A))
(DO-SOMETHING (+ XX YY) (- XX YY)))))

(WEIRD-MAY-BE-SPECIAL (ZEROP (RANDOM 2)) (+ 6 7) ii)

The term "special form" (at least in Common Lisp) has nothing to do
with whether it is built-in or user-defined. It has to do with
whether or not all of its components are evaluated in the expected
order.

ttyl,
Patrick

Quzanti

unread,
May 31, 2010, 10:35:24 AM5/31/10
to Clojure
That was interesting.

One more Q.

What determines whether special forms can be used in functions eg you
can't def a variable in a fn.

Is it there some rule or is it special form specific depending on
(a) the intended use of the special form
(b) the mechanics of getting the compiler to use the special form

Joost

unread,
May 31, 2010, 11:05:05 AM5/31/10
to Clojure

On May 31, 4:35 pm, Quzanti <quza...@googlemail.com> wrote:
> That was interesting.
>
> One more Q.
>
> What determines whether special forms can be used in functions eg you
> can't def a variable in a fn.

You can:

user> (defn fun [v] (def my-v v))
user> (fun 'a)
user> my-v
a
user> (fun 'b)
user> my-v
b

I'm not aware of any special form that can't be used inside a
function.
But I haven't looked for them either.

> Is it there some rule or is it special form specific depending on
> (a) the intended use of the special form
> (b) the mechanics of getting the compiler to use the special form

First you'd have to find such special forms.

Quzanti

unread,
May 31, 2010, 1:21:14 PM5/31/10
to Clojure
Are you sure that always works?

I think I am misunderstanding Halloway's Taxonomy of Macro's chapter

defstruct is written as a macro and Stuart then comments

"This macro looks so simple that you may be tempted to try to write it
as a function. You won't be able to because def is a special form. You
must generate def at macro time; you cannot make 'dynamic' calls to
def at runtime"

Angel Java Lopez

unread,
May 31, 2010, 1:26:55 PM5/31/10
to clo...@googlegroups.com
Hi people!

Nice explanation, about the difference of "special form" in Clojure, vs other Lisp.

I remember (Queinnec Lisp?):

lambda: to make "normal functions"
mlambda: to make "macros" (something that produce a form, and then, evaluate that result)
flambda: spread, non evaluation of parameters
nlambda: non-spread (all arguments in one variable), non evaluation of parameters.

Usually, when I wrote a Lisp interpreter, I implement the above "words".

AFAIK, Clojure doesn't have any way to build a new special form, except via macros. Why? It was a design decision? motivated by Java compilation?

Angel "Java" Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez



--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@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+u...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Meikel Brandmeyer

unread,
May 31, 2010, 1:54:07 PM5/31/10
to clo...@googlegroups.com
Hi,

On Mon, May 31, 2010 at 10:21:14AM -0700, Quzanti wrote:

> Are you sure that always works?
>
> I think I am misunderstanding Halloway's Taxonomy of Macro's chapter
>
> defstruct is written as a macro and Stuart then comments
>
> "This macro looks so simple that you may be tempted to try to write it
> as a function. You won't be able to because def is a special form. You
> must generate def at macro time; you cannot make 'dynamic' calls to
> def at runtime"

It works sometimes. Of course you can redef a Var via function.

(defn foo [y] (def x y))
(foo 5)

However, you cannot define arbitrary Vars.

(defn bar [x y] (def x y))
(bar 'c 5)

This does *not* define Var named c. So can't really make 'dynamic'
calls to def at runtime. Just as Stuart writes.

Sincerely
Meikel

Joost

unread,
May 31, 2010, 2:14:20 PM5/31/10
to Clojure
On May 31, 7:54 pm, Meikel Brandmeyer <m...@kotka.de> wrote:
> It works sometimes. Of course you can redef a Var via function.
>
> (defn foo [y] (def x y))
> (foo 5)
>
> However, you cannot define arbitrary Vars.
>
> (defn bar [x y] (def x y))
> (bar 'c 5)

True, but that's more a question of the interface provided by def. The
real problem is that if you want to access the vars defined by that
function anywhere else, they need to be defined (if not initialized)
before you can compile the code. Meaning you either have to def those
vars somewhere else (outside of a function) or make sure the function
gets called at least once before any access is mentioned in the code.

After that, you can re-define the var in any way you like.


Joost

unread,
May 31, 2010, 2:18:40 PM5/31/10
to Clojure
On May 31, 8:14 pm, Joost <jo...@zeekat.nl> wrote:
>
> True, but that's more a question of the interface provided by def. The
> real problem is that if you want to access the vars defined by that
> function anywhere else, they need to be defined (if not initialized)
> before you can compile the code. Meaning you either have to def those
> vars somewhere else (outside of a function) or make sure the function
> gets called at least once before any access is mentioned in the code.
>
> After that, you can re-define the var in any way you like.

Update: some testing indicates that that's not actually what happens.
What appears to happen is that (def) is always defining when the code
is read/compiled, no matter where in the source the def call is
actually places (like in a function definition) it's just unbound
until you assign a value to it (by "executing" the def form).

alux

unread,
Jun 1, 2010, 3:18:12 AM6/1/10
to Clojure
Hello SinDoc,

what an interesting discussion! Whoo! ;-)

Many thanks four your comment.

You wrote

> So, if you have lazy-eval, there's no need for special-forms.

This is obviousely correct for if / cond.

Looking into the other special forms ( http://clojure.org/special_forms
), I wouldnt know how to implement all of them. Certainly there is,
unknownst to me, a bunch of literature about (sets of) primitives that
cannot e replaced - literature hints anybody?

(Well, thats probably a nice set of exercises :)

Thanky and regards, alux

Sina K. Heshmati

unread,
Jun 1, 2010, 3:38:42 AM6/1/10
to clo...@googlegroups.com
"alux" <alu...@googlemail.com> said:

Hey alux,

> what an interesting discussion! Whoo! ;-)
>
> Many thanks four your comment.
>

>> So, if you have lazy-eval, there's no need for special-forms.
>
> This is obviousely correct for if / cond.
>
> Looking into the other special forms ( http://clojure.org/special_forms
> ), I wouldnt know how to implement all of them. Certainly there is,
> unknownst to me, a bunch of literature about (sets of) primitives that
> cannot e replaced - literature hints anybody?

> (Well, thats probably a nice set of exercises :)

If you're interested in programming languages, I encourage you to study SICP [1]. In chapter four, you can see variations of Scheme implemented in a metacircular way. One of these variations is a lazy evaluator (4.2 [2]). Please note that the lazy evaluator does NOT have special-forms at all.

Kind ragards,
SinDoc

[1] http://mitpress.mit.edu/sicp/full-text/book/book.html
[2] http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-27.html#%_sec_4.2

Konrad Hinsen

unread,
Jun 1, 2010, 4:44:15 AM6/1/10
to clo...@googlegroups.com
On 1 Jun 2010, at 09:18, alux wrote:

>> So, if you have lazy-eval, there's no need for special-forms.
>
> This is obviousely correct for if / cond.

If you define special forms as in Common Lisp (that's something I
learned from this discussion), yes. If you define special forms as I
think Clojure does (in fact, I can't find any definition, just a
list), then it's not true. With lazy evaluation, "if" could become a
plain function, but it would still have to be a built-in function that
one could not express in the language itself, unless some other choice
primitive or a suitable data structure exists. The notion of a
primitive operation always remains.

> Looking into the other special forms ( http://clojure.org/
> special_forms
> ), I wouldnt know how to implement all of them. Certainly there is,
> unknownst to me, a bunch of literature about (sets of) primitives that
> cannot e replaced - literature hints anybody?

For Lisp-like languages, the best starting point is SICP (http://mitpress.mit.edu/sicp/full-text/book/book.html
). For a more in-depth treatment of implementation issues, I'd
continue with Christian Queinnec's "Lisp in Small Pieces" (http://pagesperso-systeme.lip6.fr/Christian.Queinnec/WWW/LiSP.html
).

Konrad.

alux

unread,
Jun 1, 2010, 3:38:11 PM6/1/10
to Clojure
Hello Konrad,

to ensure I understand you right (I want to understand your words, so
in this very moment I dont care about other wordings):

In a lazy lisp if and cond can be plain functions. But to define plain
functions, or in any case somewhere, I need a special form.
Is it that what you mean?

(I'm always tempted to try and find the very basic blocks. But here
this seems to be like looking for a root in a directed graph - it
exists in special cases only.)

Thank you, alux



On 1 Jun., 10:44, Konrad Hinsen <konrad.hin...@fastmail.net> wrote:
> On 1 Jun 2010, at 09:18, alux wrote:
>
> >> So, if you have lazy-eval, there's no need for special-forms.
>
> > This is obviousely correct for if / cond.
>
> If you define special forms as in Common Lisp (that's something I  
> learned from this discussion), yes. If you define special forms as I  
> think Clojure does (in fact, I can't find any definition, just a  
> list), then it's not true. With lazy evaluation, "if" could become a  
> plain function, but it would still have to be a built-in function that  
> one could not express in the language itself, unless some other choice  
> primitive or a suitable data structure exists. The notion of a  
> primitive operation always remains.
>
> > Looking into the other special forms (http://clojure.org/

alux

unread,
Jun 1, 2010, 3:41:30 PM6/1/10
to Clojure
Hello SinDoc,

no special form at all? Cool, I'll have a look.

Chapter 4.1 and 4.2 actually sit on my desk already since yesterday -
I just didnt read it. I hope I get a chance in the next days.

Many thanks, alux

On 1 Jun., 09:38, "Sina K. Heshmati" <s...@khakbaz.com> wrote:
> "alux" <alu...@googlemail.com> said:
>
> Hey alux,
>
> > what an interesting discussion! Whoo! ;-)
>
> > Many thanks four your comment.
>
> >> So, if you have lazy-eval, there's no need for special-forms.
>
> > This is obviousely correct for if / cond.
>
> > Looking into the other special forms (http://clojure.org/special_forms

Konrad Hinsen

unread,
Jun 1, 2010, 4:33:41 PM6/1/10
to clo...@googlegroups.com
On 1 Jun 2010, at 21:38, alux wrote:

> In a lazy lisp if and cond can be plain functions. But to define plain
> functions, or in any case somewhere, I need a special form.
> Is it that what you mean?

Not quite, though it's true as well. What I meant is that you can't
define if/cond as a function in a language that doesn't already have a
choice function. Condition testing is a primitive operation that is
ultimately realized in hardware. So primitives always exist,
independently of laziness.

Konrad.

Sina K. Heshmati

unread,
Jun 1, 2010, 5:00:47 PM6/1/10
to clo...@googlegroups.com
alux wrote:

> no special form at all? Cool, I'll have a look.
>
> Chapter 4.1 and 4.2 actually sit on my desk already since yesterday -
> I just didnt read it. I hope I get a chance in the next days.

If you have the time and motivation, go for it. Please note that, the wizard book had better be _studied_ rather than _read_. Good luck!

SinDoc

Reply all
Reply to author
Forward
0 new messages