I am attempting to assign the variable a the parameter (list) in my function. I keep getting variable L has no value, how can I assign the variable inside the function the list parameter?
(defun pali(list)
(defvar a nil)
(defvar b nil)
(setq a (list))
(setq b (reverse list))
)
If I'm understanding correctly, what you want is
(defun pali (list)
(let ((a list))
((b (reverse list)))
...))
It's almost certainly wrong to put DEFVAR inside a function, and likely to hurt you badly if you use DEFVAR with names like A and B. DEFVAR makes a global variable, and it makes the symbol that names it "special"; everywhere you use it in future, you'll be getting the symbol-value instead of a lexical variable. Strange things will happen when you're not expecting it. That's why DEFVAR variables are usually named like A, etc., instead of just A. Use LET to make a normal lexical variable. And then there's not a lot of point setting it to NIL initially and then using SETQ to alter it, though you can do that if you like. Even just
(let (a b)
(setq a list
b (reverse list))
...)
if that's what you want [Note you can use a single SETQ to set many variables. Don't have to, of course]
Related
I want to make a macro for binding variables to values given a var-list and a val-list.
This is my code for it -
(defmacro let-bind (vars vals &body body)
`(let ,(loop for x in vars
for y in vals
collect `(,x ,y))
,#body))
While it works correct if called like (let-bind (a b) (1 2) ...), it doesn't seem to work when called like
(defvar vars '(a b))
(defvar vals '(1 2))
(let-bind vars vals ..)
Then I saw some effects for other of my macros too. I am a learner and cannot find what is wrong.
Basic problem: a macro sees code, not values. A function sees values, not code.
CL-USER 2 > (defvar *vars* '(a b))
*VARS*
CL-USER 3 > (defvar *vals* '(1 2))
*VALS*
CL-USER 4 > (defmacro let-bind (vars vals &body body)
(format t "~%the value of vars is: ~a~%" vars)
`(let ,(loop for x in vars
for y in vals
collect `(,x ,y))
,#body))
LET-BIND
CL-USER 5 > (let-bind *vars* *vals* t)
the value of vars is: *VARS*
Error: *VARS* (of type SYMBOL) is not of type LIST.
1 (abort) Return to top loop level 0.
You can see that the value of vars is *vars*. This is a symbol. Because the macro variables are bound to code fragments - not their values.
Thus in your macro you try to iterate over the symbol *vars*. But *vars* is a symbol and not a list.
You can now try to evaluate the symbol *vars* at macro expansion time. But that won't work also in general, since at macro expansion time *vars* may not have a value.
Your macro expands into a let form, but let expects at compile time real variables. You can't compute the variables for let at a later point in time. This would work only in some interpreted code where macros would be expanded at runtime - over and over.
If you’ve read the other answers then you know that you can’t read a runtime value from a compiletime macro (or rather, you can’t know the value it will have at runtime at compiletime as you can’t see the future). So let’s ask a different question: how can you bind the variables in your list known at runtime.
In the case where your list isn’t really variable and you just want to give it a single name you could use macroexpand:
(defun symbol-list-of (x env)
(etypecase x
(list x)
(symbol (macroexpand x env))))
(defmacro let-bind (vars vals &body body &environment env)
(let* ((vars (symbol-list-of vars env))
(syms (loop for () in vars collect gensym)))
`(destructuring-bind ,syms ,vals
(let ,(loop for sym in syms for bar in vars collect (list var sym)) ,#body))))
This would somewhat do what you want. It will symbol-macroexpand the first argument and evaluate the second.
What if you want to evaluate the first argument? Well we could try generating something that uses eval. As eval will evaluate in the null lexical environment (ie can’t refer to any external local variables), we would need to have eval generate a function to bind variables and then call another function. That is a function like (lambda (f) (let (...) (funcall f)). You would evaluate the expression to get that function and then call it with a function which does he body (but was not made by eval and so captures the enclosing scope). Note that this would mean that you could only bind dynamic variables.
What if you want to bind lexical variables? Well there is no way to go from symbol to the memory location of a variable at runtime in Common Lisp. A debugger might know how to do this. There is no way to get a list of variables in scope in a macro, although the compiler knows this. So you can’t generate a function to set a lexically bound symbol. And it would be even harder to do if you wanted to shadow the binding although you could maybe do it with some symbol-macrolet trickery if you knew every variable in scope.
But maybe there is a better way to do this for special variables and it turns out there is. It’s an obscure special form called progv. It has the same signature that you want let-bind to have except it works. link.
I'm trying to write a macro that takes a list of variables and a body of code and makes sure variables revert to their original values after body of code is executed (exercise 10.6 in Paul Graham's ANSI Common Lisp).
However, I'm unclear on why my gensym evaluates as I expect it to in one place, but not another similar one (note: I know there's a better solution to the exercise. I just want to figure out why the difference in evaluation).
Here's the first definition where the lst gensym evaluates to a list inside of the lambda passed to the mapcar:
(defmacro exec-reset-vars-1 (vars body)
(let ((lst (gensym)))
`(let ((,lst ,(reduce #'(lambda (acc var) `(cons ,(symbol-value var) ,acc))
vars
:initial-value nil)))
,#body
,#(mapcar #'(lambda (var) `(setf ,var (car ,lst)))
vars))))
But while it works exactly as I expect it to, it's not a correct solution to the exercise because I'm always grabbing the first element of lst when trying to reset values. I really want to map over 2 lists. So now I write:
(defmacro exec-reset-vars-2 (vars body)
(let ((lst (gensym)))
`(let ((,lst ,(reduce #'(lambda (acc var) `(cons ,(symbol-value var) ,acc))
vars
:initial-value nil)))
,#body
,#(mapcar #'(lambda (var val) `(setf ,var ,val))
vars
lst))))
But now I get an error that says #:G3984 is not a list. If I replace it with (symbol-value lst) I get an error saying variable has no value. But why not? Why does it have a value inside of the setf in lambda, but not as an argument passed to mapcar?
At macroexpansion time you try to map over the value of lst, which is a symbol at that time. So that makes no sense.
Trying to get symbol value also makes no sense, since lst's bindings are lexical and symbol-value is not a way to access that. Other bindings are not available at that time.
Clearly lst has a value at macroexpansion time: a symbol. This is what you see inside the lambda.
You need to make clear what values are computed at macroexpansion time and which at runtime.
An advice about naming:
lst is a poor name in Lisp, use list
the name lst makes no sense, since its value is not a list, but a symbol. I'd call it list-variable-symbol. Looks long, doesn't it? But it is much clearer. You would now that it is a symbol, used as the name for a variable holding lists.
I'm pretty sure you are overthinking it. Imagine this:
(defparameter *global* 5)
(let ((local 10))
(with-reset-vars (local *global*)
(setf *global* 20)
(setf local 30)
...))
I imagine the expansion is as easy as:
(defparameter *global* 5)
(let ((local 10))
(let ((*global* *global*) (local local))
(setf *global* 20)
(setf local 30)
...)
(print local)) ; prints 10
(print *global*) ; prints 5
let does the reset on it's own so you see that the macro should be very simple just making shadow bindings with let, unless I have misunderstood the assignment.
Your overly complicated macros does pretty bad things. Like getting values of global symbols compile time, which would reset them to the time the function that used this instead of before the body.
Why is my variable nodes undefined in the vector-push-extend line?
(defun make_graph (strings)
(defparameter nodes (make-array 0))
(loop for x in strings do
(vector-push-extend (make-instance 'node :data x) nodes))
n)
The short answer is that you should use let instead of defparameter to introduce your variable. For instance:
(defun make_graph (strings)
(let ((nodes (make-array 0)))
(loop for x in strings do
(vector-push-extend (make-instance 'node :data x) nodes))
;; your code says N here, but I assume that's a typo...
nodes))
The defparameter form is useful for creating "special" variables, which are somewhat similar to global variables in other programming languages. (There are some differences, e.g., the special variables introduced by defparameter aren't exactly global---instead, they are dynamically scoped, and can be let bound, etc...)
At any rate, the let form will instead create a local variable.
DEFPARAMETER is used at toplevel to define global special variables.
Toplevel:
(defparameter *foo* 42)
Still at toplevel, because forms inside PROGN are still at toplevel (by definition):
(progn
(defparameter *foo* 42)
(defparameter *bar* 32))
Not at toplevel:
(defun baz ()
(defparameter *foo* 42))
Above last form is not recognized by the compiler as a variable declaration. But when one calls (baz) and the function is running, the variable is defined and initialized.
A non-toplevel use of DEFPARAMETER will not be recognized by the compiler, but at runtime it will create a special global variable.
(defun make_graph (strings)
(defparameter nodes (make-array 0))
(loop for x in strings do
(vector-push-extend (make-instance 'node :data x) nodes))
n)
The compiler warns:
;;;*** Warning in MAKE_GRAPH: NODES assumed special
;;;*** Warning in MAKE_GRAPH: N assumed special
Thus in above code, the compiler does not recognize nodes as a defined variable, if it wasn't defined somewhere else already. The use of nodes in the function creates a warning.
Still the code might work, since at runtime the variable is created and initialized - but for every function invocation. Over and over. This compiler also assumes that nodes is just this: some kind of special variable. Still I would not count on it for all compilers.
n is also not defined anywhere.
Notes:
the correct way to introduce local lexical variables is to use LET and LET* (and other binding forms)
use DEFPARAMETER as a toplevel form. It is unusual when it's not a toplevel form. Typically the author makes a mistake then.
If I have x initialized as
(setf x 0)
Then I can change the value directly by doing
(setf x 1)
So, when using mapcar, why do I have to use the symbol-value to assign to this symbol?
(mapcar #'(lambda (a b)
(setf (symbol-value a) b))
'(x)
'(1))
Does it have something to do with the quote?
First of all, don't use setf for initialization, define variable by defvar or defparameter.
Second, you getting symbol 'X from your '(x), not a place, to use with setf, so you need to get place by symbol-value, then set it with setf macro.
I now have learnt about arrays and aref in Lisp. So far, it's quite easy to grasp, and it works like a charme:
(defparameter *foo* (make-array 5))
(aref *foo* 0) ; => nil
(setf (aref *foo* 0) 23)
(aref *foo* 0) ; => 23
What puzzles me is the aref "magic" that happens when you combine aref and setf. It seems as if aref knew about its calling context, and would then decide whether to return a value or a place that can be used by setf.
Anyway, for the moment I just take this as granted, and don't think about the way this works internally too much.
But now I wanted to create a function that sets an element of the *foo* array to a predefined value, but I don't want to hardcode the *foo* array, instead I want to hand over a place:
(defun set-23 (place)
…)
So basically this function sets place to 23, whatever place is. My initial naive approach was
(defun set-23 (place)
(setf place 23))
and call it using:
(set-23 (aref *foo* 0))
This does not result in an error, but it also doesn't change *foo* at all. My guess would be that the call to aref resolves to nil (as the array is currently empty), so this would mean that
(setf nil 23)
is run, but when I try this manually in the REPL, I get an error telling me that:
NIL is a constant, may not be used as a variable
(And this absolutely makes sense!)
So, finally I have two questions:
What happens in my sample, and what does this not cause an error, and why doesn't it do anything?
How could I solve this to make my set-23 function work?
I also had the idea to use a thunk for this to defer execution of aref, just like:
(defun set-23 (fn)
(setf (funcall fn) 23))
But this already runs into an error when I try to define this function, as Lisp now tells me:
(SETF FUNCALL) is only defined for functions of the form #'symbol.
Again, I wonder why this is. Why does using setf in combination with funcall apparently work for named functions, but not for lambdas, e.g.?
PS: In "Land of Lisp" (which I'm currently reading to learn about Lisp) it says:
In fact, the first argument in setf is a special sublanguage of Common Lisp, called a generalized reference. Not every Lisp command is allowed in a generalized reference, but you can still put in some pretty complicated stuff: […]
Well, I guess that this is the reason (or at least one of the reasons) here, why all this does not work as I'd expect it, but nevertheless I'm curious to learn more :-)
A place is nothing physical, it's just a concept for anything where we can get/set a value. So a place in general can't be returned or passed. Lisp developers wanted a way to easily guess a setter from just knowing what the getter is. So we write the getter, with a surrounding setf form and Lisp figures out how to set something:
(slot-value vehicle 'speed) ; gets the speed
(setf (slot-value vehicle 'speed) 100) ; sets the speed
Without SETF we would need a setter function with its name:
(set-slot-value vehicle 'speed 100) ; sets the speed
For setting an array we would need another function name:
(set-aref 3d-board 100 100 100 'foo) ; sets the board at 100/100/100
Note that the above setter functions might exist internally. But you don't need to know them with setf.
Result: we end up with a multitude of different setter function names.
The SETF mechanism replaces ALL of them with one common syntax. You know the getter call? Then you know the setter, too. It's just setf around the getter call plus the new value.
Another example
world-time ; may return the world time
(setf world-time (get-current-time)) ; sets the world time
And so on...
Note also that only macros deal with setting places: setf, push, pushnew, remf, ... Only with those you can set a place.
(defun set-23 (place)
(setf place 23))
Above can be written, but place is just a variable name. You can't pass a place. Let's rename it, which does not change a thing, but reduces confusion:
(defun set-23 (foo)
(setf foo 23))
Here foo is a local variable. A local variable is a place. Something we can set. So we can use setf to set the local value of the variable. We don't set something that gets passed in, we set the variable itself.
(defmethod set-24 ((vehicle audi-vehicle))
(setf (vehicle-speed vehicle) 100))
In above method, vehicle is a variable and it is bound to an object of class audi-vehicle. To set the speed of it, we use setf to call the writer method.
Where does Lisp know the writer from? For example a class declaration generates one:
(defclass audi-vehicle ()
((speed :accessor vehicle-speed)))
The :accessor vehicle-speed declaration causes both reading and setting functions to be generated.
The setf macro looks at macro expansion time for the registered setter. That's all. All setf operations look similar, but Lisp underneath knows how to set things.
Here are some examples for SETF uses, expanded:
Setting an array item at an index:
CL-USER 86 > (pprint (macroexpand-1 '(setf (aref a1 10) 'foo)))
(LET* ((#:G10336875 A1) (#:G10336876 10) (#:|Store-Var-10336874| 'FOO))
(SETF::\"COMMON-LISP\"\ \"AREF\" #:|Store-Var-10336874|
#:G10336875
#:G10336876))
Setting a variable:
CL-USER 87 > (pprint (macroexpand-1 '(setf a 'foo)))
(LET* ((#:|Store-Var-10336877| 'FOO))
(SETQ A #:|Store-Var-10336877|))
Setting a CLOS slot:
CL-USER 88 > (pprint (macroexpand-1 '(setf (slot-value o1 'bar) 'foo)))
(CLOS::SET-SLOT-VALUE O1 'BAR 'FOO)
Setting the first element of a list:
CL-USER 89 > (pprint (macroexpand-1 '(setf (car some-list) 'foo)))
(SYSTEM::%RPLACA SOME-LIST 'FOO)
As you can see it uses a lot of internal code in the expansion. The user just writes a SETF form and Lisp figures out what code would actually do the thing.
Since you can write your own setter, only your imagination limits the things you might want to put under this common syntax:
setting a value on another machine via some network protocol
setting some value in a custom data structure you've just invented
setting a value in a database
In your example:
(defun set-23 (place)
(setf place 23))
you can't do it just like that, because you have to use setf in context.
This will work:
(defmacro set-23 (place)
`(setf ,place 23))
CL-USER> (set-23 (aref *foo* 0))
23
CL-USER> *foo*
#(23 NIL NIL NIL NIL)
The trick is, setf 'knows' how to look at real place its arguments come from, only for limited number of functions. These functions are called setfable.
setf is a macro, and to use it the way you wanted to, you also have to use macros.
The reason why you have not been getting errors, is that you actually successfully modified lexical variable place which was bound to copy of selected array element.