I don't really understand, what's happening in this code and would be happy, if somebody could help me to get more insight:
(define-macro (qq)
(println (args)))
(define-macro (q)
(apply qq (args)))
Watch, how calling 'q' with a symbol or a quoted symbol adds another quote:
(q 3) => (3)
(q "abc") => ("abc")
(q x) => ('x)
(q 'x) => (''x)
(q ''x) => ('''x)
Why is that?
Thank you, Fanda
Hm... It seems like 'apply' is doing it:
(apply qq '(a b c)) => ('a 'b 'c)
(apply qq '(1 2 3)) => (1 2 3)
(apply qq '("a" "b" "c")) => ("a" "b" "c")
Fanda
PS: I have never applied macro!
Try map:
> (map qq '(a b c))
('a)
('b)
('c)
(('a) ('b) ('c))
I believe that newLISP prepares the list - symbols inside it - by quoting them. It works for functions, but doesn't work for macros.
Fanda
I'm not very sure of what you're doing but macros arent supposed to be applied or mapped.
A macro doesn't evaluate his arguments, that means that, in newLISP, any call of a macro (mac a b c d) behaves like (mac 'a 'b 'c 'd) if mac were a normal function instead of a macro.
Macros can be mapped or applied, let me explain: Fanda's example boils down to this:
(define-macro (qq) (args))
> (qq a b c)
(a b c)
> (apply qq '(a b c))
('a 'b 'c)
Here the same definition, but as a normal function:
(define (qq) (args))
> (qq a b c)
(1 2 3)
> (apply qq '(a b c))
(a b c)
You see that the macro must behave like it does, or it would be a normal function evaluating it's arguments. The following comparison shows that macros can be applied and mapped and simulate the behavior of a normal function. First the behavior of the built-in +:
> (set 'a 1 'b 2 'c 3)
> (+ a b c)
6
> (apply + '(a b c))
value expected in function + : 'a
> (apply + '(1 2 3))
6
> (map + '(1 2 3) '(10 20 30))
(11 22 33)
Now the same as a macro:
(define-macro (my+) (apply + (map eval (args))))
> (my+ a b c)
6
> (apply my+ '(a b c))
value expected in function + : 'a
> (apply my+ '(1 2 3))
6
> (map my+ '(1 2 3) '(10 20 30))
(11 22 33)
both produce the same results behaving the same way in map and apply situations.
Lutz
By the way, I always wanted to get something clarified and so I might as well ask it now. The manual says (under define-macro) that
Quote
Macros in newLISP are similar to define functions, but they do not evaluate their arguments. New functions can be created to behave like built-in functions that delay the evaluation of certain arguments. Since macros can access the arguments inside a parameter list, they can be used to create flow-control functions like those already built into newLISP.
Now, I've always taken this to mean that the only difference between lambda and lambda-macro is that the former takes on evaluated arguments and the latter takes on unevaluated arguments. Is this right?
I was always under this impression (if correct or not) because nowhere in the newlisp runtime strategy could I see a separate macro expansion step (as in Common Lisp). Everything seems to happen at run-time, i.e. dynamically. The downside is that you can't pre-process your macro sexps, but the upside is that macros in newlisp are much easier to write, debug and understand than their Common Lisp counterparts. I think the upside is much bigger than the downside, and a good design decision for newlisp.
Thanks for any clarification.
I didn't mean you can't map or apply macro. What I meant to say is that if you are going to map 'n' apply your macro everywhere, it probably wants to be a function, not a macro.
if not, which would be a good example (I can't think of anything, but maybe I'm being too scheme/commonlispy
edit: BTW, when you're in the top level in common lisp, a macro also works dinamically. Macros work different in newLisp cause in common lisp you return a list of code which is then evaled in the place of the macro. In newlisp you don't need to do that because of dynamic scope, you don't return a list of code, you just execute it in place. Or am I wrong?
Yes Rickyboy, this is exactly how it is, evaluation of parameters is the only difference.
In Common LISP as a compiled language it makes sense to have expansion as part of the macro functionality, while in newLISP as a dynamic language you use extra functions for this, like 'expand' or 'letex' doing the work during runtime.
Often you can allleviate the runtime impact of expansion by using function currying or other function factory techniques. This way the expansion work is done only once when fabricating the function.
Having template expansion as a separate functionality means also that you can use it outside of macros, e.g. inside normal functions or even outside at the toplevel in a script file.
Lutz
nikus80,
If my understanding of newlisp macros is correct (cf. my post above), they are not macros in the Common Lisp vein, just functions (i.e. lambdas) that take on unevaluated arguments. Hence, the requirement for newlisp macros is not their potential "applicability", but rather if the programmer needs to delay evaluation of arguments during function application.
The advantage of having such "macros" is that they are as easy to reason with as functions, and as I said before, this is a big plus for application development.
Lutz will clarify this soon, no doubt.
All the best! --Ricky
Ah! Lutz came in with the clarification as I was (slowly) composing my last message. Thanks once again, Lutz! You are the faster gunslinger.
--Rickyboy
Yes Rickyboy, exactly, see my previous post, we posted at the same moment (and again :)).
To Nikus80: dynamic scoping is not related to all this.
Lutz
No, what I meant to say is that newLisp-like macros are only useful with dynamic scope. They're useless with lexical scope since the code you receive often refers the current enviroment variables.
I agree with Lutz -- I don't see what the usefulness of newlisp macros has to do with the scope (or extent) of variables. The type of variable scope of a language such as newlisp has only to do with how the *free* variables are evaluated in an s-expression, not the *bound* variables. The parameters of a function (or a newlisp macro) delineate the bound (i.e. not free) variables in the body of the lambda(-macro). And it turns out that the variables bound by a lambda have the same treatment whether we have lexical or dynamic variable scope in our language. It's the free variables we have to worry about -- they are treated differently if we have lexical versus dynamic scope. Hence, any argument about how parameters, i.e. bound variables, are treated (as in the function-versus-macro issue we were talking about) has nothing to do with the variable scope's effect on the value of free variables.
suppose newLisp had lexical scoping. Forget macros for a second.
imagine there is a function mydolist that receives a quoted code, and very much behaves like dolist
(set 'lst '(1 2 3))
(let (a 3)
(mydolist '(e lst)
'(+ a 3)))
when mydolist calls eval on '(+ a 3), what is the value of a? 3, you say. But only with dynamic scope. with lexical scope, if mydolist calls eval, it's evaled in the lexicals scope where mydolist was defined, which could be very different from the actual and where a could be undefined. So, with lexical scope, you have to receive a list and eval it in the current scope. Something like
(let (a 3)
(eval (mydolist '(e lst) '(+ a 3))))
which, by the way, is exactly how common lisp macros work.
about appling macros, I thought about it and I could think of a place to use the technique. But it didn't worked.
(define-macro (my-or)
(let (val (eval (args 0)))
(if val val (apply my-or (rest (args))))))
this mimicks the recursive definition of (or) of scheme or common lisp.
This doesn't work because of the mystery quoting. If I call my-or with
(my-or nil (cons 2 3))
it returns the list (cons 2 3), not (2 3).
I think that, if applied. a macro should behave like a normal function. Usually, when you're appling a macro, you've already prevented it's argument from evaluation.
To my-or to work, you have to write it as a function, then make the macro a call to it.
(define (fun-my-or2 )
(let (val (eval (args 0)))
(if val
val
(apply fun-my-or2 (rest (args))))))
(define-macro (my-or2 )
(apply fun-my-or2 (args)))
of course, i guess is no big deal. you could write a (define-recursive-macro) to do the hard work. But still, I think is not the desired behavior.
... or you could write your function like this:
(define-macro (my-or)
(let (val (eval (args 0)))
(if val val (apply my-or (rest (map eval (args)))))))
(my-or nil (cons 2 3)) => (2 3)
but the same logic than can be easier rewritten as a normal function, because all arguments are evaluated:
(define (my-or)
(if (args 0) (args 0) (apply my-or (rest (args)))))
(my-or nil (cons 2 3)) => (2 3)
or even shorter
(define (my-or p)
(if p p (apply my-or (args))))
(my-or nil (cons 2 3)) => (2 3)
Lutz
ps: note that none of the definitions (of you and me) handle the case where all arguments evaluate to nil, which could be handled like this:
(define (my-or p)
(if p p (if (args) (apply my-or (args)) p)))
Quote from: "nikus80"
suppose newLisp had lexical scoping. Forget macros for a second.
imagine there is a function mydolist that receives a quoted code, and very much behaves like dolist
(set 'lst '(1 2 3))
(let (a 3)
(mydolist '(e lst)
'(+ a 3)))
when mydolist calls eval on '(+ a 3), what is the value of a? 3, you say. But only with dynamic scope. with lexical scope, if mydolist calls eval, it's evaled in the lexicals scope where mydolist was defined, which could be very different from the actual and where a could be undefined. So, with lexical scope, you have to receive a list and eval it in the current scope. Something like
(let (a 3)
(eval (mydolist '(e lst) '(+ a 3))))
which, by the way, is exactly how common lisp macros work.
Right! That's why a 'mydolist' CL macro shouldn't call 'eval' in its definition (and one reason why CL and Scheme PL experts discourage its general use in this way), for it would break the semantic model I described in my last post. Now, because CL macros behave the way you describe, we can write "variable quantifiers" (which bind variables in the scope of their expressions (not their definitions)) in lexically scoped languages. This is how 'dolist' can respect the outer binding of 'a' by the 'let' in CL. This boils down to the fact that, even in lexically scoped languages, the bound variables are taken care of and we have to worry about how the free variables get their values (cf. my previous post).
Quote from: "nikus80"
about appling macros, ... I think [this] is not the desired behavior.
Ah yes, our original topic. (Sorry, Fanda.) What do you think about this?
(define-macro (my-or)
(let ((v (eval (args 0))))
(cond ((= (length (args)) 1) v) ; base case
((empty? (args)) nil) ; degenerate case
(true
(if v
v
(apply-macro my-or (rest (args))))))))
(define (apply-macro macro arglist)
(letex (macapp (cons macro (map quote arglist)))
(eval macapp)))
I believe apply-macro works when used for nested macro calls where apply would be needed (e.g. in the tail call of a recursive definition of a macro, as in this version of my-or); apply-macro's job, via its call to eval is to prevent the accumulation of successive quotes. And there may be a better scheme to play than this, since it doesn't seem to have general application (geeky pun intended), as seen in this usage with Fanda's qq macro:
> (apply-macro qq '(a b c))
('a 'b 'c)
invalid function : ('a 'b 'c)
called from user defined function apply-macro
It's *almost* there -- it's just doing one eval too many. :-) In this case, I'd use apply, as Lutz did
> (apply qq '(a b c))
('a 'b 'c)
('a 'b 'c)
It does seem to me that apply is the culprit in Fanda's situation. I originally thought that it was the nested macro call that caused the problem, but this little test disabused me of that notion.
;; Here's a macro with a nested macro call of its argument.
(define-macro (myq)
(letex (arg1 (args 0))
(qq arg1)))
> (myq 'x)
('x)
('x)
;; Ah, this worked! But recall 'q' which uses 'apply':
> (q 'x)
(''x)
(''x)
Lutz, any words of wisdom? --Rick
It all boils down to this: does 'apply' evaluate the elements in the arguments list, or does it not?
(set 'a 1 'b 2 'c 3)
(+ a b c) => 6
(apply + '(a b c)) => value expected in function + : 'a
we see that 'apply' does not evaluate a,b and c.
(set 'a nil 'x 9)
(my-or nil (cons 2 3)) => (2 3)
(my-or a (cons 2 3)) => (2 3)
(my-or x (cons 2 3)) => 9
(apply-macro my-or '(nil (cons 3 4))) => (3 4)
(apply-macro my-or '(a (cons 2 3))) => nil ; the evaluated a (*)
(apply-macro my-or '(x (cons 2 3))) => 9
'apply-macro' seems to work like this: apply the macro or function on the un-evaluated elements, and then evaluate the result. But this can be accomplished easier like this:
(eval (apply my-or '(nil (cons 3 4)))) => (2 3)
(eval (apply my-or '(a (cons 2 3)))) => nil
(eval (apply my-or '(x (cons 2 3)))) => 9
The results are the same as with 'apply-macro', just wrapping the 'apply' with an 'eval':
(apply-macro macro argslist)
; the same as
(eval (apply macro argslist))
'apply-macro' works just like 'apply' except it evaluates the result.
My point is this: the whole issue is about the specific evaluation rules 'apply' should follow, and it should apply these rules consistently to functions and macros. When you deal with a big API you don't always know if a function you are using is a macro or normal function.
Lutz
ps: all other 'my-or' in a previous post show the same results
(*) This seems inconsistent with the result of the normal execution of 'my-or' but is consistent with the rule: first apply on unevaluated, then evaluate result.
it doesnt seems to work.
I need my-or to eval only the arguments needed. my-or as a function is not what I need.
(define (prit)
(print "printed!"))
(define (ret-nil)
'())
(define-macro (my-or)
(let (val (eval (args 0)))
(if val val (eval (apply my-or (rest (args)))))))
That doesn't work, because of the mystery quoting/appling problem.
try (my-or nil (ret-nil) (cons 2 3) (prit)), it returns '(). The my-or suggested by ricky returns '() too.
I think what you're receiving is the quoted list '(ret-nil), you eval it and it's still a non-null list, so it returns the list. then its evaled, and it returns the empty list. This is not desired.
About not knowing something is a macro or a function I can't understand why would I want macro and functions to behave identically, especially when I know macros don't have any speed execution advantage. When I use dolist, I know it's a macro. When I use my-or, I know it's a macro and I know it only evals what is needed and that it wont eval (prit).
Quote from: "Lutz"
My point is this: the whole issue is about the specific evaluation rules 'apply' should follow, and it should apply these rules consistently to functions and macros.
I completely agree. My opinion is that 'apply' works just fine - it needs to be consistent.
Fanda
'my-or' can be written as this:
(define-macro (my-or)
(if (empty? (args))
nil
(if (or (eval (args 0)) (= 1 (length (args))))
(eval (args 0))
(eval (cons 'my-or (rest (args)))))))
> (my-or nil (ret-nil) (cons 2 3) (prit))
(2 3)
Fanda
Nikus80: it does work with this changed definition of your macro:
(define-macro (my-or)
(let (val (eval (args 0)))
(if val val (apply my-or (rest (map eval (args)))))))
; and this better one if all members in the list are nil)
(define (my-or p)
(if p p (if (args) (apply my-or (args)) p)))
and works with all others I posted together with this one earlier.
Lutz
... and it works also with Fanda's latest definition:
(set 'x 9 'a nil)
> (eval (apply my-or '(nil (cons 3 4))))
(3 4)
> (eval (apply my-or '(a (cons 3 4))))
nil
> (eval (apply my-or '(x (cons 3 4))))
9
>
Lutz
Fanda, that's cool! that's exactly what I was wanting to do with apply!
for the rest, there is something I'm doing wrong? They don't work!
(define (prit)
(print "printed!"))
(define (ret-nil)
'())
(define-macro (my-or)
(let (val (eval (args 0)))
(if val val (apply my-or (rest (map eval (args)))))))
(define (my-or2 p)
(if p p (if (args) (apply my-or2 (args)) p)))
(define-macro (my-or3)
(if (empty? (args))
nil
(if (or (eval (args 0)) (= 1 (length (args))))
(eval (args 0))
(eval (cons 'my-or3 (rest (args)))))))
(define (fun-my-or2 )
(let (val (eval (args 0)))
(if val
val
(apply fun-my-or2 (rest (args))))))
(define-macro (my-or4 )
(apply fun-my-or2 (args)))
> (my-or nil (ret-nil) (cons 2 3) (prit))
printed!(2 3)
> (my-or2 nil (ret-nil) (cons 2 3) (prit))
printed!(2 3)
> (my-or3 nil (ret-nil) (cons 2 3) (prit))
(2 3)
> (my-or4 nil (ret-nil) (cons 2 3) (prit))
(2 3)
>
EDIT: (define (my-or p) (if p p (if (args) (apply my-or (args)) p))) has the same problem
'my-or3' also double evaluates on this one:
> (my-or3 nil (prit) (cons 2 3) (ret-nil))
printed!printed!"printed!"
>
but this definition finally seems to be ok:
(define (prit) (print "printed!"))
(define (ret-nil) '())
(define-macro (my-or)
(let (v (eval (args 0)))
(if v v (if (args) (eval (cons 'my-or (rest (args))))))))
> (my-or nil (prit) (cons 2 3) (ret-nil))
printed!"printed!"
> (my-or nil (ret-nil) (cons 2 3) (prit))
(2 3)
Lutz
So, what is the current status of this thread? I will take a shot.
(1) Once you all worked out the my-or argument evaluation issues, when the dust settled, the most progress seemed to be made by Fanda who introduced the (eval (cons 'my-or (rest (args)))) tail call idiom.
(2) We haven't yet found, for my-or, a tail call idiom involving apply which works. (Of course, I'm not talking about the non-recursive implementation of my-or we figured out many days ago -- and which works fine). And whether we can find such a call is still an open question.
(3) Fanda's original question, i.e. why does (q 'x) yield (''x), is still an open question.
Have I missed anything?
Finally, I wanted to say (before I forget again) "thank you" for a great discussion thread. I had to get back to office work the past two days, so I couldn't participate more, but when I had the time, I really enjoyed thinking about the issue. Thanks, --Rick
Here an explanation again for the quote-effect, this time in a different way:
The 'qq' macro is basically a list maker, taking un-evaluated arguments, while 'list' is a list maker evaluating arguments:
> (define-macro (qq) (args))
> (list 'a 'b 'c)
(a b c)
> (qq a b c)
(a b c)
If you agree on the outcome of above examples, you have to agree upon the following behavior of 'qq' too.
> (apply list '('a 'b 'c))
('a 'b 'c)
> (apply qq '(a b c))
('a 'b 'c)
If the applied 'qq' whould not quote the list members it would behave like 'list', which it is not.
Lutz
I see what you mean.
(apply list '('a 'b 'c)) is equivalent to (list ''a ''b ''c)
so,
(apply qq '(a b c)) is equivalent to (qq 'a 'b 'c)
the thing is, I can't get rid of the quotes! with list, I can.
(apply list (list a b c)) is equivalent to (list a b c)
(apply qq (list a b c)) is not equivalent to (qq a b c)
In the first one, (list a b c) is evaled, then the resulting list is applied with list, without evaling its arguments since I've already evaled them. This works fine, since list is a function, and all it's arguments are evaled anyway. It works with any function btw.
Now, with apply qq, it isn't very straightforward. Cause (apply qq (list a b c)) is meant to work with functions only, that's what I meant early when I said applying a macro just felt weird. With apply, I can't get something that translates to (qq a b c). so the answer to "We haven't yet found, for my-or, a tail call idiom involving apply which works." is guess is: we won't.
The thing is, it does not matters. Just use fanda's idiom. Or better, make it a macro or something.
at first I thought:
(define-macro (fapply)
(eval (cons (args 0) (eval (args 1)))))
but it doesn't works. I think is because
(define-macro (my-or)
(let (v (eval (args 0)))
(if v v (fapply my-or (rest (args))))))
when fapply evals (rest (args)), it thinks args refers to fapply args, not my-or args. I don't know which is the workaround to that. But for the moment, since there is no need to quote the first argument, just use:
(define (fapply)
(eval (cons (args 0) (args 1))))
still, like I said, I'm not happy with applying macros unless it's inside another macro, which in that case I probably need fapply, not apply.