There is something special about special forms. A basic set of special forms is needed and can't be implemented as macros.
There is something special about special forms. A basic set of special forms is needed and can't be implemented as macros.
It doesn't have to be built into the language; it could be a macro based on COND or even on WHEN/UNLESS. But…
> A basic set of special forms is needed and can't be implemented as macros.
One has to have some special forms in order to build everything else as macros. And in practice, of course, there can be some big efficiency gains to having lots of special forms vice having only a few and lots of macrology.
In Common Lisp IF is built in and COND is a macro. One of the conditionals needs to be built-in.
http://www.lispworks.com/documentation/HyperSpec/Body/s_if.h...
> One has to have some special forms in order to build everything else as macros.
For conditionals, one conditional needs to be there, into which the other macro-based conditionals can be expanded.
> And in practice, of course, there can be some big efficiency gains to having lots of special forms vice having only a few and lots of macrology.
Not really. Common Lisp has a minimum of special forms and usually has some of the faster Lisp implementations.
That's actually not true. IF can be implemented in terms of LAMBDA.
(defun _true (then else) then)
(defun _false (then else) else)
(defmacro _if (condition then else)
`(funcall (funcall (function ,condition) (lambda () ,then) (lambda () ,else))))
? (_if _true (print 123) (print 456))
123
123
? (_if _false (print 123) (print 456))
456
456
?[UPDATE]
You have to make some minor tweaks to my original code to make it work. Here's a fully tested version:
(defun _true (then else) then)
(defun _false (then else) else)
(defmacro _if (condition then else)
`(funcall (funcall ,condition (lambda () ,then) (lambda () ,else))))
(setf (get t 'altboolean) '_true)
(setf (get nil 'altboolean) '_false)
(defun ->altboolean (condition) (get condition 'altboolean))
(defun _fact (n)
(_if (->altboolean (<= n 1)) 1 (* n (_fact (1- n)))))>> In Common Lisp IF is built in and COND is a macro. One of the conditionals needs to be built-in.
> That's actually not true.
The context was about Common Lisp, not Haskell nor Scheme (of course other languages do things as they wish, including lazy evaluation). There need to be at least one conditional built-in in CL in order to map generalized booleans to {T, NIL}. This conditional could even be eager, but there has to be a construct which selects the approprate value. Which of the other 24 special forms is suitable?
As implemented, it's not quite a drop-in replacement for IF, but it can be made so by rolling the call to ->ALTBOOLEAN in to the _IF macro.
> The context was about Common Lisp
Yes, I know that. The example code is written in Common Lisp.
> there has to be a construct which selects the approprate value
Yes. LAMBDA can do that.
> Which of the other 24 special forms is suitable?
LAMBDA. It can be used both to select the appropriate value and to delay evaluation. LAMBDA is really all you need. Making IF a special form is just an optimization.
> LAMBDA.
I am nitpicking, but LAMBDA is not a special form, FUNCTION/FLET/LABELS are: http://www.lispworks.com/documentation/HyperSpec/Body/03_aba...
> It's a pretty elementary exercise to fix ->altboolean so that this invariant is maintained.
And how do you map generalized booleans to your functions?
Right now, I can think of two possible ways. You can map NIL to #'_false in a hash-table, and use (gethash nil table #'_true) to provide a default value. Or you can also write a generic function:
(defgeneric ->altboolean (x)
(:method ((x null)) #'_false)
(:method (x) #'_true))
There could be other ways, but as far as I know, none of them are portable, because even though it is allowed for all defined CL operators to be implemented as built-ins, you generally cannot expect or assume that it is done so (see gethash in CCL and SBCL). As far as you know, and even though it would be terribly inefficient, they could all be implemented only by combining special forms.If you discard IF, can you perform the elementary exercise using only special forms? I cannot imagine how, but I honestly would like to be shown a working approach.
You certainly are.
> can you perform the elementary exercise using only special forms?
I don't even need any special forms. All I need to do is use the default argument to GET.
CL-USER 16 > (defparameter a 0)
A
CL-USER 17 > (if (foo) (foo) (foo))
T
CL-USER 18 > a
4
CL-USER 19 > (defparameter a 0)
A
CL-USER 20 > (_if (->altboolean (foo)) (foo) (foo))
T
CL-USER 21 > a
5
Given that foo is defined as: (defmacro foo () (incf a) '(progn (incf a) t))
4 vs. 5Does not look like a true replacement for IF in Common Lisp...
I'm not talking about Lambda Calculus and related.
I'm talking about Lisp implementation. Real world Lisp implementation.
(Also note that Lisp macros don't have to be all written in Lisp. They are just expander functions. When you're bootstrapping a Lisp, you can write macros in the bootstrapping language. So the chicken-and-egg problem of "how do you write the first macros if there are no special forms" doesn't exist. You write the raw functions in assembly, or C or whatever, and register them as macro-expanders.)