How can I pass a variable to a macro in common lisp? - common-lisp

For a program, I'm trying to use a macro such as this one to simplify my code downstream and avoid repeating the same code again and again:
(defmacro destructure (values &body body)
`(let* ((other-values (rest values))
(age (getf other-values :age))
(len (getf other-values :len))
(all (getf other-values :all)))
(progn ,#(loop for e in body collect `(,#e)))))
It is supposed to work with a list such as this:
'(name :age 1 :len 2 :all '(1 2 3 4 5))
The idea is that I should be able to run this code:
(destructure '(name :age 1 :len 2 :all '(1 2 3 4 5))
(type-of age)
(first all))
Or, using a variable, like this:
(setf *values* '(name :age 1 :len 2 :all '(1 2 3 4 5)))
(destructure *values*
(type-of age)
(first all))
Instead of having to access the different elements each time. Of course this is a simplified example, but the list that I have to work on is reality is much longer.
I'm finding it extremely hard to do this. Basically, the code above does not work (unless I cheat by setfing a global variable "values" to hold my list) because the macro is treating the symbol "values" just as that, without expanding the list that it should point to.
On the other hand, I can't use a regular function because then the instructions I'm passing in the body are immediately executed, but I have to place them in the let.
I'm new enough to the language and I believe that I'm probably missing something, and that there probably is a way to achieve it. Is there?

First of all, for your problem you can use destructuring-bind:
(destructuring-bind (name &key age len all)
'(name :age 1 :len 2 :all (1 2 3 4 5))
(list (type-of age)
(type-of len)
(type-of name)
(first all)))
⇒ (BIT (INTEGER 0 4611686018427387903) SYMBOL 1)
Now, some notes about your code:
You have put the reference to values inside a backquote, so it is not a reference to the macro argument, but instead a free reference of the expanded form to some outside variable named values. What you probably meant to do:
(defmacro destructure (values &body body)
`(let* ((other-values ,(rest values)))
(age (getf other-values :age))
(len (getf other-values :len))
(all (getf other-values :all)))
…))
This has a problem in that it shadows any variable named other-values from outside the macro call form. You should use gensyms to avoid that:
(defmacro destructure (values &body body)
(let ((other-values (gensym "other-values")))
`(let* ((,other-values ,(rest values)))
(age (getf other-values :age))
(len (getf other-values :len))
(all (getf other-values :all)))
…))
A note about your code template:
(progn ,#(loop for e in body collect `(,#e))
simplifies to
(progn ,#(loop for e in body collect e))
simplifies to
(progn ,#body)
and since the body of a let already is an implicit progn:
,#body
Finally, your example data:
(name :age 1 :len 2 :all '(1 2 3 4 5))
is actually:
(name :age 1 :len 2 :all (quote (1 2 3 4 5)))
The reader always expands ' to a quote form. When you nest quote forms, you are almost always doing something wrong.

You need to evaluate the values variable in the macro:
? (defmacro destructure (values &body body)
`(let* ((other-values (rest ,values))
(age (getf other-values :age))
(len (getf other-values :len))
(all (getf other-values :all)))
(progn ,#body)))
DESTRUCTURE
? (destructure '(name :age 1 :len 2 :all '(1 2 3 4 5))
(print (type-of age))
(print (first all)))
;Compiler warnings :
; In an anonymous lambda form at position 0: Unused lexical variable LEN
BIT
QUOTE
QUOTE
The QUOTE in the data is not what you want. Quoted data does not need internal quotes.
? (destructure '(name :age 1 :len 2 :all (1 2 3 4 5))
(print (type-of age))
(print (first all)))
;Compiler warnings :
; In an anonymous lambda form at position 0: Unused lexical variable LEN
BIT
1
1
It also works with a variable:
? (let ((values '(name :age 1 :len 2 :all (1 2 3 4 5))))
(destructure values
(print (type-of age))
(print (first all))))
;Compiler warnings :
; In an anonymous lambda form at position 59: Unused lexical variable LEN
BIT
1
1
?
You can also declare the three variables as ignorable. This will silence the warnings above.
What to fix?
The variable other-values is visible in the body.

Related

(push x nil) VS (push x place-that-stores-the-empty-list)

Why is it not possible to push directly on a list like '(1 2 3) or NIL?
Specifically:
Why is possible to do
> (let ((some-list nil))
(push 42 some-list))
(42)
but not to do something like
(push 42 nil)
or
(push 42 '(1 2 3))
What is the reasoning behind this implementation?
With macro push the second argument needs to be a place to be modified. Here are some examples:
Lets make two variables:
(defparameter *v* (list 2 4))
(defparameter *v-copy* *v*)
Then we push 0
(push 1 *v*) ; ==> (1 2 4)
*v-copy* ; ==> (2 4) (unaltered)
; the reason is that the variable is changed, not its value
(macroexpand '(push 1 v))
; ==> (setq v (cons 1 v))
push can use other things as second argument. Lets try a cons
(push 3 (cdr *v-copy*))
*v-copy* ; ==> (2 3 4)
; since the tail of *v* is the *v-copy* *v* is changed too
*v* ; ==> (1 2 3 4)
(macroexpand-1 '(push 2 (cdr *v-copy*)))
; ==> (rplacd v (cons 2 (cdr *v-copy*)))
If your examples were valid, what should it really have done? Lets do the nil first:
(macroexpand '(push 42 nil))
; ==> (setq nil (cons 42 nil))
This treats nil just as any other variable and if this worked nil would never be the empty list again. It would have been a list with one element, 42 and a different value than (). In Common Lisp nil is a constant and cannot be mutated. I've created a lisp once where nil was a variable like any other and a small typo redefined nil making the programs behave strange with no apparent reason.
Lets try your literal quoted list.
(macroexpand '(push 42 (quote (1 2 3))))
; ==> (let ((tmp (1 2 3)))
; (funcall #'(setf quote) (cons 42 'tmp) tmp))
It doesn't seem the push macro differentiates between special form quote and those types that has set their setf function. It won't work and it doesn't make sense. Anyway in the same manner as mutating the binding nil if this changed the literal data '(1 2 3) to '(43 1 2 3) would you then expect to get (43 1 2 3) every time you evaluated (1 2 3) from there on? I imagine that would be the only true effect of mutating a constant. If this was allowed you should be allowed to redefine 4 to be 5 so that evaluating 4 or (+ 2 2) shows the result 5.

common lisp function/macro aliases

I would like to set aliases in common lisp(clisp to be exact) for commands that are used a lot, such as "defun" and "lambda" etc, is it possible to do this?
This is actually kind of a duplicate of this question, but I can not comment and the solution does not work for defun or lambda in both sbcl and clisp
Macros:
CL-USER 5 > (setf (macro-function 'dm) (macro-function 'defmethod))
#<Function DEFMETHOD 410009A014>
CL-USER 6 > (dm m1+ ((v vector)) (map 'vector #'1+ v))
#<STANDARD-METHOD M1+ NIL (VECTOR) 4130003913>
CL-USER 7 > (m1+ #(1 2 3 4))
#(2 3 4 5)
The whole point by macros is to provide a source rewriting service.. Thus I want to give you this and you can make that out of it:
(defmacro df (name (&rest arguments) &body body)
`(defun ,name ,arguments ,#body))
(df test (x) (+ x x))
(test 5) ; ==> 10
We have just shortened the name.. Lets make another one:
(defmacro df1 (name &body body)
`(defun ,name (_) ,#body))
(df1 test (+ _ _))
(test 5) ; ==> 10
And so on...

Pointers in Common Lisp

I want to save a reference (pointer) to a part of some Data I saved in another variable:
(let ((a (list 1 2 3)))
(let ((b (car (cdr a)))) ;here I want to set b to 2, but it is set to a copy of 2
(setf b 4))
a) ;evaluates to (1 2 3) instead of (1 4 2)
I could use macros, but then there would ever be much code to be executed if I want to change some Data in the middle of a list and I am not very flexible:
(defparameter *list* (create-some-list-of-arrays))
(macrolet ((a () '(nth 1000 *list*)))
(macrolet ((b () `(aref 100 ,(a))))
;; I would like to change the macro a here if it were possible
;; but then b would mean something different
(setf (b) "Hello")))
Is it possible, to create a variable as a reference and not as a copy?
cl-user> (let ((a '(1 2 3)))
(let ((b (car (cdr a))))
(setf b 4))
a)
;Compiler warnings :
; In an anonymous lambda form: Unused lexical variable B
(1 2 3)
A cons cell is a pair of pointers. car dereferences the first, and cdr dereferences the second. Your list is effectively
a -> [ | ] -> [ | ] -> [ | ] -> NIL
| | |
1 2 3
Up top where you're defining b, (cdr a) gets you that second arrow. Taking the car of that dereferences the first pointer of that second cell and hands you its value. In this case, 2. If you want to change the value of that pointer, you need to setf it rather than its value.
cl-user> (let ((a '(1 2 3)))
(let ((b (cdr a)))
(setf (car b) 4))
a)
(1 4 3)
If all you need is some syntactic sugar, try symbol-macrolet:
(let ((a (list 1 2 3 4)))
(symbol-macrolet ((b (car (cdr a))))
(format t "~&Old: ~S~%" b)
(setf b 'hello)
(format t "~&New: ~S~%" b)))
Note, that this is strictly a compile-time thing. Anywhere (in the scope of the symbol-macrolet), where b is used as variable, it is expanded into (car (cdr a)) at compile time. As Sylwester already stated, there are no "references" in Common Lisp.
I wouldn't recommend this practice for general use, though.
And by the way: never change quoted data. Using (setf (car ...) ...) (and similar) on a constant list literal like '(1 2 3) will have undefined consequences.
Building on what Baggers suggested. Not exactly what you are looking for but you can define setf-expanders to create 'accessors'. So lets say your list contains information about people in the for of (first-name last-name martial-status) and when someone marries you can update it as:
(defun marital-status (person)
(third person))
(defun (setf marital-status) (value person)
(setf (third person) value))
(let ((person (list "John" "Doe" "Single")))
(setf (marital-status person) "Married")
person)
;; => ("John" "Doe" "Married")

Unexpected behavior with loop macro and closures

Why do these forms behave this way?
CL-USER>
(setf *closures*
(loop for num in (list 1 2 3 4)
collect (lambda ()
num)))
(
#<COMPILED-LEXICAL-CLOSURE #x302004932E1F>
#<COMPILED-LEXICAL-CLOSURE #x302004932DCF>
#<COMPILED-LEXICAL-CLOSURE #x302004932D7F>
#<COMPILED-LEXICAL-CLOSURE #x302004932D2F>)
CL-USER>
(funcall (first *closures*))
4
CL-USER>
(funcall (second *closures*))
4
I would have expected the first funcall to return 1, and the second to return 2, etc. This behavior is consistent with both Clozure Common Lisp and Steel-Bank Common Lisp implementations.
If I rework the loop macro to a version using dolist, what I'd expect is what's returned:
(setf *closures*
(let ((out))
(dolist (item (list 1 2 3 4) (reverse out))
(push (lambda () item) out))))
(
#<COMPILED-LEXICAL-CLOSURE #x302004A12C4F>
#<COMPILED-LEXICAL-CLOSURE #x302004A12BFF>
#<COMPILED-LEXICAL-CLOSURE #x302004A12BAF>
#<COMPILED-LEXICAL-CLOSURE #x302004A12B5F>)
CL-USER>
(funcall (first *closures*))
1
CL-USER>
(funcall (second *closures*))
2
CL-USER>
What's going on with the loop macro version?
num is same variable shared by all lambdas.
Use
(setf *closures*
(loop for num in (list 1 2 3 4)
collect (let ((num1 num))
(lambda ()
num1))))
num1 is fresh variable for each iteration.
As of dolist, "It is implementation-dependent whether dolist establishes a new binding of var on each iteration or whether it establishes a binding for var once at the beginning and then assigns it on any subsequent iterations." (CLHS, Macro DOLIST). So it may work on one implementation and fail on other.
The name num represents the same binding during the evaluation of LOOP.
Maybe you want to write:
(mapcar 'constantly (list 1 2 3 4))
to get what you meant.

Difference between `set`, `setq`, and `setf` in Common Lisp?

What is the difference between "set", "setq", and "setf" in Common Lisp?
Originally, in Lisp, there were no lexical variables -- only dynamic ones. And
there was no SETQ or SETF, just the SET function.
What is now written as:
(setf (symbol-value '*foo*) 42)
was written as:
(set (quote *foo*) 42)
which was eventually abbreviavated to SETQ (SET Quoted):
(setq *foo* 42)
Then lexical variables happened, and SETQ came to be used for assignment to them too -- so it was no longer a simple wrapper around SET.
Later, someone invented SETF (SET Field) as a generic way of assigning values to data structures, to mirror the l-values of other languages:
x.car := 42;
would be written as
(setf (car x) 42)
For symmetry and generality, SETF also provided the functionality of SETQ. At this point it would have been correct to say that SETQ was a Low-level primitive, and SETF a high-level operation.
Then symbol macros happened. So that symbol macros could work transparently, it was realized that SETQ would have to act like SETF if the "variable" being assigned to was really a symbol macro:
(defvar *hidden* (cons 42 42))
(define-symbol-macro foo (car *hidden*))
foo => 42
(setq foo 13)
foo => 13
*hidden* => (13 . 42)
So we arrive in the present day: SET and SETQ are atrophied remains of older dialects, and will probably be booted from eventual successors of Common Lisp.
(set ls '(1 2 3 4)) => Error - ls has no value
(set 'ls '(1 2 3 4)) => OK
(setq ls '(1 2 3 4)) => OK - make ls to (quote ls) and then have the usual set
(setf ls '(1 2 3 4)) => OK - same as setq so far BUT
(setf (car ls) 10) => Makes ls '(10 2 3 4) - not duplicated by setq/set
You can use setf in place of set or setq but not vice versa since setf can also set the value of individual elements of a variable if the variable has individual elements. See the exaples below:
All four examples will assign the list (1, 2, 3) to the variable named foo.
(set (quote foo) (list 1 2 3)) ;foo => (1 2 3)
(1 2 3)
(set 'foo '(1 2 3)) ;foo => (1 2 3) same function, simpler expression
(1 2 3)
(setq foo '(1 2 3)) ;foo => (1 2 3) similar function, different syntax
(1 2 3)
(setf foo '(1 2 3)) ;foo => (1 2 3) more capable function
(1 2 3)
setf has the added capability of setting a member of the list in foo to a new value.
foo ;foo => (1 2 3) as defined above
(1 2 3)
(car foo) ;the first item in foo is 1
1
(setf (car foo) 4) ;set or setq will fail since (car foo) is not a symbol
4
foo ;the fist item in foo was set to 4 by setf
(4 2 3)
However, you can define a symbol macro that reprents a single item within foo
(define-symbol-macro foo-car (car foo)) ; assumes FOO => (1 2 3)
FOO-CAR
foo-car ;foo-car is now a symbol for the 1st item in foo
1
(setq foo-car 4) ;set or setq can set the symbol foo-car
4
foo ;Lisp macros are so cool
(4 2 3)
You can use defvar if you have not already defined the variable and do not want to give it a value until later in your code.
(defvar foo2)
(define-symbol-macro foo-car (car foo2))
setq is just like set with a quoted first arg -- (set 'foo '(bar baz)) is just like (setq foo '(bar baz)). setf, on the other hand, is subtle indeed -- it's like an "indirection". I suggest http://www.n-a-n-o.com/lisp/cmucl-tutorials/LISP-tutorial-16.html as a better way to get started understanding it than any answer here can give... in short, though, setf takes the first argument as a "reference", so that e.g. (aref myarray 3) will work (as the first arg to setf) to set an item inside an array.
One can think of SET and SETQ being low-level constructs.
SET can set the value of symbols.
SETQ can set the value of variables.
Then SETF is a macro, which provides many kinds of setting things: symbols, variables, array elements, instance slots, ...
For symbols and variables one can think as if SETF expands into SET and SETQ.
* (macroexpand '(setf (symbol-value 'a) 10))
(SET 'A 10)
* (macroexpand '(setf a 10))
(SETQ A 10)
So SET and SETQ are used to implement some of the functionality of SETF, which is the more general construct. Some of the other answers tell you the slightly more complex story, when we take symbol macros into account.
I would like to add to previous answers that setf is macro that call specific function depending on what was passed as its first argument.
Compare results of macro expansion of setf with different types of arguments:
(macroexpand '(setf a 1))
(macroexpand '(setf (car (list 3 2 1)) 1))
(macroexpand '(setf (aref #(3 2 1) 0) 1))
For some types of arguments "setf function" will be called:
(defstruct strct field)
(macroexpand '(setf (strct-field (make-strct)) 1))

Resources