41

The below obviously doesn't work and hence this question.

How do I correct the below code so that the value of somelist becomes '(("abc" . 123)) ?

(setq x "abc")
(setq y 123)
(setq somelist nil)
(add-to-list 'somelist '(x . y))
20
  • 6
    Have you tried quasiquoting? Try `(,x . ,y).
    – Dan
    Jan 17, 2015 at 21:13
  • 2
    Questions considered as duplicates of this one recur very often. Can someone come up with a way to make it more clear to beginners that this question/answer is what they're looking for? I suspect part of the problem is that the title of this question only makes sense if you already know the root cause of the problem (i.e. you kind of know the answer). I'm trying to imagine myself as a user who has no idea that variables need to be evaluated and even less of an idea what the "quote" means, but am coming empty. @Drew?
    – Stefan
    Oct 10, 2018 at 13:04
  • 1
    @stefan: Unlike the case where there is an error message (which can be used in the question title of a community Q+A), the error, if any, resulting from quoting something that needs to be evaluated (and this is a particular case of that) can be far afield of the site of the quoting. More commonly, there is no (Emacs) error - just behavior that doesn't correspond to what the user wanted.
    – Drew
    Oct 10, 2018 at 14:36
  • 1
    @Stefan: No great question title comes to mind for this. But we could at least formulate a question that tackles it directly, including perhaps a "normal" case that call for just removing a quote mark and a case that calls for quasiquoting. A good Q, covering such cases, and a good answer covering them, would be helpful. But as for finding Qs that are duplicates: without an error message in the Q title it requires reading the whole question and knowing how to find the duplicate to point to.
    – Drew
    Oct 10, 2018 at 14:40
  • 1
    @ScottWeldon: It would be good for the Q&A for this common topic to not seem to be about just, say, variables. That's all I meant. This question could be edited to better reflect the underlying (more general) question. The rationales: (1) make it easier to find and (2) present the problem & solution(s) at a more useful level of generality. But I agree that this question is the best one we have for this problem. Thanks for the point and link about the value of dups.
    – Drew
    May 7, 2020 at 20:57

2 Answers 2

41

The general issue is that you need x and y to be evaluated before they get inserted in somelist. The issue with the quoted list (with ' as reader syntax) is that quote is a special form that does not evaluate its argument. According to the docstring:

(quote ARG)

Return the argument, without evaluating it. (quote x) yields x. Warning: quote does not construct its return value, but just returns the value that was pre-constructed by the Lisp reader...

Hence, you either need to backquote or use a function that evaluates the arguments.

Backquoting allows you to evaluate elements of a backquoted list selectively with the , syntax:

(setq x "x-val" y "y-val" z "z-val" somelist nil)
'(x  y z)                            ; => (x y z)
`(x ,y z)                            ; => (x "y-val" z)
(add-to-list 'somelist `(x y ,z))    ; => ((x y "z-val"))

Alternately, you can use cons (as @tarsius suggests in his answer) or, for an arbitrary number of elements, list:

(add-to-list 'somelist (cons x y))   ; => (("x-val" . "y-val"))
(setq somelist nil)                  ; reset
(add-to-list 'somelist (list x y z)) ; => (("x-val" "y-val" "z-val"))

Which to use depends on what you need to do with the elements.

2
  • Sorry, I have read this and other answers over and over, but am still clueless how to do that. That's because everywhere lists are used, but what if I don't have lists? What if I have just the 'x from your answer. No lists, 'x is an argument passed to a function (like (foo 'x)), and inside the function I need both the 'x (to mutate it), and the value of x which is "x-val" in your code. So, no lists. Then, how do I get the value of 'x out of it (i.e. evaluate it)? I tried a bunch of combinations with backticks, commas, and @s, to no avail.
    – Hi-Angel
    Aug 9, 2021 at 20:38
  • I found out: one needs eval. So, calling (eval 'x) will return "x-val". Worth mentioning in the answer I think, because similar questions are marked as duplicates of this page.
    – Hi-Angel
    Aug 10, 2021 at 6:29
21

Do not quote the cons cell, because quoted expressions are not evaluated. That's exactly why one quotes - to prevent evaluation. But that's not what you want, so don't.

Instead use the form that creates a cons cell from two evaluated values, its arguments.

(cons x y)

Of course you can also quasiquote but that doesn't really make sense here, and looks worse. Only use ` and , when that improves readability, i.e. when doing something more complex than constructing a cons cell or adding an atom or list at the beginning of some existing list.

Using quasiquoting it would look like this:

`(,x . ,y)

Which is worse because it uses additional syntax which isn't required at all in this case and obfuscates that cons is being used.

3
  • 3
    Good point on consing. Quasiquoting strikes me as being more about fine-grained control of the list contents rather than readability, but I agree that the use-case makes sense for cons.
    – Dan
    Jan 17, 2015 at 23:02
  • Thank you for your answer. That was a great TIL moment for me. I was blindly putting quotes before lists and cons. Jan 17, 2015 at 23:02
  • 1
    @Dan, well yes - and no. Quasiquoting cannot do anything that you couldn't do with just cons, list, and nconc. Except being prettier. It's syntactic sugar which is useful when you need "fine-grained control of the list contents" (as in "doing something more complex than adding an atom or list at the beginning"). And the added benefit of using that syntactic sugar is: readability. Quasiquoting doesn't give you additional more fine-grained control - it just allows you to do the same thing with fewer bugs in the initial attempt. :-)
    – tarsius
    Jun 22, 2015 at 18:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.