lisp macro Q

Bacardi151

Senior member
Dec 15, 2003
540
0
0
first of all, yes i know this is the wrong forum, but this gets most traffic and i know there are CS guys out here, so let me just try to squeeze this question in real quick

im trying to write a macro that takes 0 or more variables and sets them all to 0 (in lisp its for hwk)

the only thing i can think of that to do that can take a variable number of arguments is to use &rest , which actually creates a list of the rest of the arguments taken. problem is that when i try to take car of the list, and change the value to 0, it doesnt actually do so

i believe this is an instance of this
i.e.
(setf x 2 y 3 z 4)
(setf a (list x y z)) -> now a = (2 3 4)
(setf (car a) 0)
it doesnt change x to 0, but it does change a -> (0 3 4) as opposed to (2 3 4)

since taking the arguments as a list wont cut it, what other way is there to take a variable number of arguments for a macro??

i can easily write a macro that takes a fixed number of arguments and convert its values to 0, but i just cant figure out how to do it when the number of variables passed is not set.

open to any tips and suggestion on solving this macro problem, thx
 

xirtam

Diamond Member
Aug 25, 2001
4,693
0
0
I find it humorous that everyone who posts a programming question here always mentions that they know it's the wrong forum but that it gets more visibility.
 

xirtam

Diamond Member
Aug 25, 2001
4,693
0
0
Why don't you just find the length of the input list and then produce a new list with that number of elements, each being 0?
 

Bacardi151

Senior member
Dec 15, 2003
540
0
0
Originally posted by: xirtam
Why don't you just find the length of the input list and then produce a new list with that number of elements, each being 0?

i probably have to clarify that i'm not trying to change the content of the list that's created in the macro, but im trying to change the each individual value that's passed to the macro

i.e. , x initially was 3. when i do (ZERO x) then x becomes 0.

because this is a macro and in lisp, it doesnt return anything, it should only generate code that automatically sets any variable to 0 which is suppose to save you time to write (setf x 0) (setf y 0) etc. and instead just write (ZERO x y)..
 

Bacardi151

Senior member
Dec 15, 2003
540
0
0
Originally posted by: xirtam
I find it humorous that everyone who posts a programming question here always mentions that they know it's the wrong forum but that it gets more visibility.

what's so humorous about it? at least we're being honest, and it is the truth after all. the hwk is due tomorrow, and i haven't gotten a single response in the software/programming forum. im just growing a bit desperate for some suggestions. nobody's twisting your arm to look in this thread
 

esun

Platinum Member
Nov 12, 2001
2,214
0
0
I learned some Scheme and I believe it is similar to lisp, but in scheme to take a variable number of arguments you do something like this:

(define (func x y . z) ...function body...)

Where x and y are definite arguments, and z is a list of your other arguments (variable number).

In Scheme there's also a function called "map" which applies a function to a list of things. So I think something like this (or similar) should work:

(define (func . y) (map (lambda (x) (set! x 0)) y))

Something like that, anyway.

Edit: Yeah, that won't work. The problem is that you get passed copies of variables, so set! only sets the local copy, while the original remains unchanged. We learned mutation like set-car! and set-cdr!, and those may be your best bet, but you'll have to write a different function obviously.
 

Bacardi151

Senior member
Dec 15, 2003
540
0
0
esun, thanks for your suggestions.

yeah that does look like lisp. instead of the .z, lisp uses &rest z , which means takes the remaining arguments and put it in a list.

problem here is that, like you indicated, they're not the actual variables in the list, instead what happens is that it assigns z the values of the variables rather than just the variables itself.

i.e. it'll be something like

(set z (x y w)), where perhaps x y w are already set to 1 2 3 respectively, then z becomes (1 2 3) instead of simply (x y w)

so when i do a (set (car z) 0) it actually just changes first position in the list to 0 and not x to 0.

this is a tricky one, and yes i've tried writing another macro that calls itself recursively and passes the cdr of the list and it has a condition that says if the list is null then exit. it all works fine, except for the part that it doesnt set the global variables that are passed to the macro to 0, instead the global variables that are passed to the macro are set into a local variable inside the macro and once it's done generating and evaluating the code, the local variable is long gone and nothing really happened.
 

eLiu

Diamond Member
Jun 4, 2001
6,407
1
0
Originally posted by: Bacardi151
first of all, yes i know this is the wrong forum, but this gets most traffic and i know there are CS guys out here, so let me just try to squeeze this question in real quick

im trying to write a macro that takes 0 or more variables and sets them all to 0 (in lisp its for hwk)

the only thing i can think of that to do that can take a variable number of arguments is to use &rest , which actually creates a list of the rest of the arguments taken. problem is that when i try to take car of the list, and change the value to 0, it doesnt actually do so

i believe this is an instance of this
i.e.
(setf x 2 y 3 z 4)
(setf a (list x y z)) -> now a = (2 3 4)
(setf (car a) 0)
it doesnt change x to 0, but it does change a -> (0 3 4) as opposed to (2 3 4)

since taking the arguments as a list wont cut it, what other way is there to take a variable number of arguments for a macro??

i can easily write a macro that takes a fixed number of arguments and convert its values to 0, but i just cant figure out how to do it when the number of variables passed is not set.

open to any tips and suggestion on solving this macro problem, thx

The reason your 'set-bang' or whatever LISP users call it doesn't have the behavior you desire is that putting x y z into a list puts their VALUES into the list, not the variables themslves. So the list a and the vars x y z are separate entities...so your (setf (car a) 0) only modifies the list and cannot touch the actual vars.

If you need to set variables to 0, you need to have some function that takes those vars as an input (use a variable # of inputs...i forget what the syntax is), and like recursively step through until you've hit everyone of the inputs.

I THINK that's the fastest way to do it...

Edit: why are you taking LISP? God I hate LISP/Scheme :( lol
 

Bacardi151

Senior member
Dec 15, 2003
540
0
0
Originally posted by: eLiu
Originally posted by: Bacardi151
first of all, yes i know this is the wrong forum, but this gets most traffic and i know there are CS guys out here, so let me just try to squeeze this question in real quick

im trying to write a macro that takes 0 or more variables and sets them all to 0 (in lisp its for hwk)

the only thing i can think of that to do that can take a variable number of arguments is to use &rest , which actually creates a list of the rest of the arguments taken. problem is that when i try to take car of the list, and change the value to 0, it doesnt actually do so

i believe this is an instance of this
i.e.
(setf x 2 y 3 z 4)
(setf a (list x y z)) -> now a = (2 3 4)
(setf (car a) 0)
it doesnt change x to 0, but it does change a -> (0 3 4) as opposed to (2 3 4)

since taking the arguments as a list wont cut it, what other way is there to take a variable number of arguments for a macro??

i can easily write a macro that takes a fixed number of arguments and convert its values to 0, but i just cant figure out how to do it when the number of variables passed is not set.

open to any tips and suggestion on solving this macro problem, thx

The reason your 'set-bang' or whatever LISP users call it doesn't have the behavior you desire is that putting x y z into a list puts their VALUES into the list, not the variables themslves. So the list a and the vars x y z are separate entities...so your (setf (car a) 0) only modifies the list and cannot touch the actual vars.

If you need to set variables to 0, you need to have some function that takes those vars as an input (use a variable # of inputs...i forget what the syntax is), and like recursively step through until you've hit everyone of the inputs.

I THINK that's the fastest way to do it...

Edit: why are you taking LISP? God I hate LISP/Scheme :( lol

yeah i kind of noticed that i'm simply putting the values of the variables into the list.

so let me clarify something.

when i write (defmacro ZERO (&rest ARGS)...)

does it mean when i call ZERO and pass x y z, it only passes the values of x y z to the macro and then puts the values in the list? is there anyway that i can pass the variables itself?

another thing is that, i know i can use the quasi-quote which means don't evalute...meaning i wont evalute X Y and Z to its values....but at some point i will have to evaluate them ...say when i take car or cdr of the list ARGS, and at that point the list ARGS content will just be values and not variables....so yeah i dont see a way to take a number of variables (that doesnt get evaluted) and i know i can't create a function for this, because functions always evaluates their arguments before executing them in the code.

and im taking lisp because i need to take core elective courses for CS major, and lisp was the only other thing offered that fitted my schedule.

 

Bacardi151

Senior member
Dec 15, 2003
540
0
0
and yeah i've tried a few methods . 1 is using tail recursion and you pass the cdr of the list (cutting off the top and passing the rest) until the list becomes empty and then exit, but through each recursion it sets the first in the list to 0. of course this doesnt work, as it doesnt treat the first in the list as a variable...

and i've also tried a do loop, but that too doesnt work for the same reason.
 

eLiu

Diamond Member
Jun 4, 2001
6,407
1
0
Originally posted by: Bacardi151
and yeah i've tried a few methods . 1 is using tail recursion and you pass the cdr of the list (cutting off the top and passing the rest) until the list becomes empty and then exit, but through each recursion it sets the first in the list to 0. of course this doesnt work, as it doesnt treat the first in the list as a variable...

and i've also tried a do loop, but that too doesnt work for the same reason.

lol wow im sorry i made that recursion suggestion...of course that doesn't work :/

What's happening is when you evaluate a function in lisp, it creates a local environment for that function...and the variables are all defined in the local environment. So you need to access the original location of the vars...uh...

Can you modify the interpreter? If you make it do dynamic scoping, then it would access the variables from the caller environment, not the function environment...

edit: I'm using the words frame & environment interchangeably...that's kind of wrong but i hope you get the idea...
 

Bacardi151

Senior member
Dec 15, 2003
540
0
0
problem is, my teacher is going to run the code and he wants it to run without modifying anything, and it should run universally on any lisp machine.
 

Bacardi151

Senior member
Dec 15, 2003
540
0
0
on another note im writing a macro which in particular that can take 0 or more variables, so what's my options? can i do it any other way than using &rest, since that will convert the variables to a list, and once that's done i'll lose my variables.
 

eLiu

Diamond Member
Jun 4, 2001
6,407
1
0
im tinkering w/this a little while studying for a final...but tell me if this bit of code helps you at all:

(define bar2
(lambda ()
(eval '(define y 10) (environment-parent (the-environment) ))))

That will create a variable y in the environment that calls bar2.

I think you're going to have to do something like this (explicitly telling the scheme evaluator to work in a certain environment), except yours will use the set command...

You may have to like make a function that will create the '(blahblahblah) code to set up the piece that needs to be evaluated...similar to the procedure for "desugaring" an or statement into nested if statements. (does that make any sense)

I'll mess with it some more to see if i come up with anything...

Edit: look at this...
(define x 10)
(define y 5)
(define (bar4 lst)
(let ((temp lst))
`(set! ,(car temp) 0)))

(define foo
(lambda ()
(eval (bar4 (list 'y 'x)) (environment-parent (the-environment))))

(foo)

now y is set to 0...didn't touch x though.

Also observe that (bar4 (list 'y 'x)) results in:
(set! y 0)
(unevaluated expression, which is passed to eval in foo)


I think you're going to want to create a sequence of these things.

Like if (cdr temp) is not null, then have bar4 call itself again with the cdr of temp...so in the end it'll create an expression like this:

(begin
(set! x1 0)
(set! x2 0)
(set! x3 0)
...
(set! x-last 0)
)

then pass that whole thing to eval, using whatever environment you need to use...

edit2: I dont know if that's the best method, but it will work...
I had to do some similar stuff for an intro class when I had to turn or statements into a series of if's, turn let's into a series of lambdas, and so on...'desugaring' is what they called it
 

Bacardi151

Senior member
Dec 15, 2003
540
0
0
hi, eliu

i'm guessing you're writing in scheme, and i'm not sure how the syntax for the (environment-parent (the-environment)) portion would be in lisp, as i'm still a newbie in lisp. on another note, i realized something that slipped my mind and i gotta really thank you for it, because it puts me in a new and more clear path to try to solve this. basically it was the 'x 'y part. before i would just do a (list x y) and not the actual atoms x y which needs the quote part in front of them. because if i do a (setf a (list x y)) and if x and y were defined as 5 and 10 respectively, it simply sets a to (5 10) , but with (setf a (list 'x 'y)) it sets a to (x y).

i'm going to try to have a macro that passes the list of 'x and 'y as a list to another macro that will try to recursively call itself until the list that was passed to it (i.e. (list 'x 'y)) becomes null and then exits the macro.

i'm really grateful for your effort i think i may be able to solve it now (hopefully), and hey, i'll let you go back to studying for your final, i'd hate if this were to get to u and distract ur studying but good luck on your final!
 

eLiu

Diamond Member
Jun 4, 2001
6,407
1
0
Originally posted by: Bacardi151
hi, eliu

i'm guessing you're writing in scheme, and i'm not sure how the syntax for the (environment-parent (the-environment)) portion would be in lisp, as i'm still a newbie in lisp. on another note, i realized something that slipped my mind and i gotta really thank you for it, because it puts me in a new and more clear path to try to solve this. basically it was the 'x 'y part. before i would just do a (list x y) and not the actual atoms x y which needs the quote part in front of them. because if i do a (setf a (list x y)) and if x and y were defined as 5 and 10 respectively, it simply sets a to (5 10) , but with (setf a (list 'x 'y)) it sets a to (x y).

i'm going to try to have a macro that passes the list of 'x and 'y as a list to another macro that will try to recursively call itself until the list that was passed to it (i.e. (list 'x 'y)) becomes null and then exits the macro.

i'm really grateful for your effort i think i may be able to solve it now (hopefully), and hey, i'll let you go back to studying for your final, i'd hate if this were to get to u and distract ur studying but good luck on your final!

lol this final is driving me nuts so distractions are good...

Yeah i'm coding in Scheme.

What you're suggesting doesn't work in Scheme unless I was typing it in wrong. Though I couldn't say how it's setup in LISP, lol.

But in spirit, yes that's what needs to happen. You have to set! the variable, not the value. My code will do it...probably in a more general case than is really necessary.
 

Bacardi151

Senior member
Dec 15, 2003
540
0
0
ok, im not sure how you did it, but when i set a to (list 'x 'y), i do get (x y) for a. but then when i do a `(setf ,(car a) 0) it displays (SETF X 0) .....(to verify what it actually outputs and this is what i want...X appearing in the SETF......however when i actually evaluate (setf (car a) 0) it doesn't set X to be 0, and X is still 3, instead it still just evaluates a's list to (0 Y) :T
 

Bacardi151

Senior member
Dec 15, 2003
540
0
0
btw, what does lambda() in ur functions mean?

right now, i think the only thing that's hindering me from doing this is how do i evaluate X and Y which is inside a list set to A.

i know you somehow managed to do it, when you did this `(set! ,(car temp) 0)))

but i tried that and it still doesn't work for me. although i didn't use the let statement, what difference does it actually make?
 

eLiu

Diamond Member
Jun 4, 2001
6,407
1
0
lambda is the code that creates a function...

like
(define (bar x)
(+ x x)
)
takes x and doubles it...

This is equivalent to:
(define bar
(lambda (x)
(+ x x))
)

So when I have lambda (), then I mean a function w/no parameters.

Try it with the let statement. A let statement is a lot like a function...for example:
(let ((a 10) (b 20))
(+ a b))
returns: 30

this is equivalent to:
((lambda (a b)
(+ a b)
10 20)

So let is like an implicit function.

What it does it creates another frame that's subordinate to the frame of the function (bar4 in this case) which holds a local copy of the list. In this case, it SHOULD make no difference...I do it out of habit b/c in some other situations it's handy to have the let.

Also, were you using the bit with eval and environments?

Edit: can i see the your scheme code?

Edit2:
ok, im not sure how you did it, but when i set a to (list 'x 'y), i do get (x y) for a. but then when i do a `(setf ,(car a) 0) it displays (SETF X 0) .....(to verify what it actually outputs and this is what i want...X appearing in the SETF......however when i actually evaluate (setf (car a) 0) it doesn't set X to be 0, and X is still 3, instead it still just evaluates a's list to (0 Y) :T

Yes that's what it should do. (setf (car a) 0) sets the car of a (first element of the list) to be 0, it does not modify X.

What I did was basically
1) extract x from the list (car lst)
2) set up the proper syntax for evaluation `(set! ,(car lst) 0)
3) use the function w/form (eval *expression* *environment*) to evaulate the piece from step2.
 

Bacardi151

Senior member
Dec 15, 2003
540
0
0
hi eliu

i finally got it to work!!

i looked at your code over and over again and i tried the (eval function. i wasn't sure if it would work in lisp, but it did, and that was the missing key!

because basically when i do the `(setf ,(car var) 0), it would never evaluate it i suppose, so i applied the (eval `(setf....etc. just like in ur bar4, and it worked smoothly. so i tried doing a tail recursion call to fix the rest of the list, well i didnt get that right, i kept getting overstacking so i guess somehow it just recursed forever or whatnot.

anyways i did a do loop and it works just great. thanks a lot dude, this is a really heavy burden lifted off of my back. and it's gonna help a lot when i write macros which i suspect we'll be doing for the rest of the quarter.

the great part of macros which eliminated a lot of the extra work is that the macros takes the arguments as is, they dont evaluate them, so i didnt have to apply the backquote to prevent the evaluation before i actually needed to. but anyways, i can't thank you enough, i've spent the past 2 days trying to figure it out and a few hours online today doing it and im glad u were on today hehe. so anyways, good luck to you on ur finals, and i guess u'll have to find another distraction now :p

edit: oh btw, i was thinking lambda had something to do with that, but i didn't see lambda() in your bar4 function so that threw me off.
 

eLiu

Diamond Member
Jun 4, 2001
6,407
1
0
Originally posted by: Bacardi151
hi eliu

i finally got it to work!!

i looked at your code over and over again and i tried the (eval function. i wasn't sure if it would work in lisp, but it did, and that was the missing key!

because basically when i do the `(setf ,(car var) 0), it would never evaluate it i suppose, so i applied the (eval `(setf....etc. just like in ur bar4, and it worked smoothly. so i tried doing a tail recursion call to fix the rest of the list, well i didnt get that right, i kept getting overstacking so i guess somehow it just recursed forever or whatnot.

anyways i did a do loop and it works just great. thanks a lot dude, this is a really heavy burden lifted off of my back. and it's gonna help a lot when i write macros which i suspect we'll be doing for the rest of the quarter.

the great part of macros which eliminated a lot of the extra work is that the macros takes the arguments as is, they dont evaluate them, so i didnt have to apply the backquote to prevent the evaluation before i actually needed to. but anyways, i can't thank you enough, i've spent the past 2 days trying to figure it out and a few hours online today doing it and im glad u were on today hehe. so anyways, good luck to you on ur finals, and i guess u'll have to find another distraction now :p

edit: oh btw, i was thinking lambda had something to do with that, but i didn't see lambda() in your bar4 function so that threw me off.

Great! Yeah the way LISP is evaluated (my class calls it the Environmental Model) takes some getting used to...it's a bit weird and definitely different from mainstream languages like Java or C++. But the eval statement is definitely necessary b/c that forces scheme to evaluate (setf x 0) instead of (setf (car a) 0)...2 very different things!

-Eric

edit: yeah there are some random 'shorthand' expresions in scheme...like you can get rid of the lambda in some cases to save yourself some typing. Sorry about that :)

edit2: feel free to shoot me any other questions you have about LISP. I'm about to have my finals period, so I may not respond immediately but I'm glad to help...
 

eLiu

Diamond Member
Jun 4, 2001
6,407
1
0
one more thing...

Have they taught you guys the environmental model? This problem seems a bit unfair w/o knowledge of how that works (unless there's a far better way to solve this one than what i proposed, haha)...

If they haven't and you have some free time, you might check this out. It's "Structure and Interpretation of Computer Programs" by the MIT press (it's free & legal).

This is the book used for my class at MIT...I find it a bit confusing at times...but then again there are many who find it very useful & easy to read.