I'm learning Lisp. I'm implementing solution to some relatively simple problem. I'm thinking of list that represents initial state of problem like this
((0 1) (2 3) (5 4))
I want to create variable and assign that list to it. I've tried
(let ((initial-state ((0 1) (2 3) (5 4)))))
but this won't compile. After that I've tried
(let ((initial-state list (list 0 1) (list 2 3) (list 5 4))))
this works, but it's too long. Is there better way to do this?
(let ((initial-state '((0 1) (2 3) (4 5))))
...)
The ' expands to (quote ...) which basically means "don't evaluate this, just return it to me as a list". It's used to separate data from code (which in lisp are related concepts).
Do you mean this?
(let ((initial-state '((0 1) (2 3) (5 4)))) ...)
That single quote is a quote. :)
More about quoting here:
When to use 'quote in Lisp
Wikipedia article on Lisp
Related
I am experiencing a behavior of the push function that I don't get. Maybe someone could explain to me why Lisp behaves this way.
Supposed I define a list as a global variable, and then try to push a new value to it using the following code:
(defparameter *primes* '(3 5 7 11))
(push 2 *primes*)
Then *primes* is now (2 3 5 7 11). So far, so good.
Now I try to do the same thing, but without the *primes* variable, i.e.:
(push 2 '(3 5 7 11))
The result is an error message:
EVAL: 3 is not a function name; try using a symbol instead
Now I have two questions:
Why does this not work? I would expect that push returns the list (2 3 5 7 11), why does this not happen? Where am I wrong?
Apart from that, I don't get the error message. What is Lisp trying to tell me with 3 is not a function name? Of course, 3 is not a function name, but I don't try to call a function named 3 anywhere, do I?
Any help is appreciated :-)
If you read the CL Hyperspec for PUSH, you will read that push expects a place.
A place is something like a variable, a structure slot, a class slot, an array access, or similar. Since Lisp uses linked cons cells for lists, it does not make sense to push something in front of a cons cell, without a reference for that.
So above is simple: we can't push to a direct list.
Why this error message?
This gets a bit complicated...
(push 2 '(3 5 7 11))
Is actually:
(push 2 (quote (3 5 7 11))
A function can be a place, it then needs a corresponding setter function. Here the setter is thought to be (setf quote) - that's right, Common Lisp can sometimes have lists as function names, not only symbols.
If we look at the macroexpansion of above:
? (pprint (macroexpand '(push 2 (quote (3 5 7 11)))))
(LET* ((#:G328 2) (#:G327 (3 5 7 11)) (#:G326 (CONS #:G328 '#:G327)))
#:G327
#:G326
(FUNCALL #'(SETF QUOTE) #:G326 #:G327))
You can see that it tries to call the setter. But it also thinks that (3 5 7 11) is a Lisp form.
I give you an example, where it actually works, but we don't use quote, but a real accessor function:
CL-USER 40 > (let ((v (vector (list (list 'a 'b 'c) (list 'd 'e 'f))
(list (list 1 2 3) (list 4 5 6)))))
(print v)
(push 42 (first (aref v 1)))
(print v)
(values))
#(((A B C) (D E F)) ((1 2 3) (4 5 6)))
#(((A B C) (D E F)) ((42 1 2 3) (4 5 6)))
In above first is the getter and CL knows the corresponding setter. The form (aref v 1) is the call and returns the index 1 element of the vector. We are then pushing to the first list of the element.
Your call has a similar structure and (3 5 7 11) is at a similar position as (aref v 1). The Lisp system says that in (3 4 7 11) then number 3 is not a valid function. Which is correct. But the real error was about the push operation. Since the macro could not detect the error, the error gets later detected in the macro expanded code.
I have found only the emacs lisp manual push, but I guess it behaves similar for Common Lisp
— Macro: push element listname
This macro creates a new list whose car is element and whose cdr is the list specified by listname, and saves that list in listname.
So it seems push is modifying its argument listname, which isn't possible with a literal list. To do what you have in mind, one would use cons instead.
To the second part 3 is not a function name, I would say push, or some function inside it, tries to evaluate the literal list. Evaluating (3 5 7 11) means, call the function 3 with arguments 5 7 11. Hence the error message.
Again from emacs, Ctrl-h f push
push is a Lisp macro in `cl.el'.
(push X PLACE)
Insert X at the head of the list stored in PLACE.
Analogous to (setf PLACE (cons X PLACE)), though more careful about
evaluating each argument only once and in the right order. PLACE may
be a symbol, or any generalized variable allowed by `setf'.
setf in turn allows place to be a
symbolic references such as (car x) or (aref x i)
which explains, why push evaluates the second argument.
I think you need CONS in second case:
(cons 2 '(3 5 7 11)) => (2 3 5 7 11)
This question already has answers here:
Test if array is inside a list in lisp
(1 answer)
Remove duplicate strings from a list
(1 answer)
Closed 8 years ago.
How do i remove duplicated lists inside a list in common-lisp?
I tried this:
(remove-duplicates '( (1 2 3) (1 2 3)))
But it evaluates to ((1 2 3) (1 2 3)), not ((1 2 3)).
Thanks.
Use the keyword argument :test to specify the function that defines whether or not two items are duplicates of each other. Most lisp functions, including remove-duplicates, use eql to test for equality by default. eql is much stricter than equal, which is what you probably want to be using.
(remove-duplicates '((1 2 3) (1 2 3)) :test #'equal)
This evaluates to '((1 2 3)).
See this post for more detail about the difference between eql and equal.
Try:
(remove-duplicates '((1 2 3) (1 2 3)) :test #'equal)
Is there a way to define a racket macro foo so that
(list 1 (foo 2 3) 4)
expands into
(list 1 2 3 4)
?
It's currently not possible (and seems unlikely to change in the near future).
Here's one thread discussing this. See in particular the answer by Matthew Flatt:
allowing splicing of results in function-call
subexpressions would break equivalences that are currently exploited by
macros and the compiler.
As other answers have mentioned, you cannot have a macro expand into more than one value, and have that spliced into the calling context. But you can do something similar using quasiquotation.
Assuming your macro is adapted to return a list instead, you can do this (for your given example):
`(1 ,#(foo 2 3) 4)
Example (tested in Racket):
> `(1 ,#(map sqrt '(2 3)) 4)
'(1 1.4142135623730951 1.7320508075688772 4)
This question already has an answer here:
Test if array is inside a list in lisp
(1 answer)
Closed 2 years ago.
(remove '(1 2) '((1 2) (1 3)))
doesn't remove '(1 2) from list in common lisp. (I think it uses eq and not equal).
Do we have any other alternative to delete element from list of lists in common lisp?
(remove '(1 2) '((1 2) (1 3)) :test #'equal)
After understanding (quote), I'm curious as to how one might cause the statement to execute. My first thought was
(defvar x '(+ 2 21))
`(,#x)
but that just evaluates to (+ 2 21), or the contents of x. How would one run code that was placed in a list?
(eval '(+ 2 21))
#Christián Romo:
Backtick example: you can kinda implement apply using eval and backtick, because you can splice arguments into a form. Not going to be the most efficient thing in the world, but:
(eval `(and ,#(loop for x from 1 upto 4 collect `(evenp ,x))))
is equivalent to
(eval '(and (evenp 1) (evenp 2) (evenp 3) (evenp 4)))
Incidentally, this has the same result as the (much more efficient)
(every 'evenp '(1 2 3 4))
Hope that satisfies your curiosity!
Take a look at funny Lisp tutorial at http://lisperati.com/. There are versions for Common Lisp and Emacs Lisp, and it demonstrates use of quasiquote and macros.