I have the following structure on LISP
(setf *books* '(
(
(:tit 'Titulo1)
(:aut (quote Autor1) )
(:gen 'Genero1)
(:score 99)
)
(
(:tit 'Titulo2)
(:aut (quote Autor2) )
(:gen 'Genero2)
(:score 40)
)
))
Now, I want to reset all scores to zero, using mapcar and lambda. I try
(
defun reset(list)
(mapcar
(lambda(libro)
'(
(:tit (assoc :puntuacion libro))
(:aut (assoc :aut libro) )
(:gen (assoc :gen libro))
(:score 0)
)
)
list
)
)
The point is that assoc is not being evaluated inside the lambda function. How can I access the initial object?
>Solution :
You are quoting your code, so the following:
'((:tit (assoc :puntuacion libro))
(:aut (assoc :aut libro) )
(:gen (assoc :gen libro))
(:score 0))
… is not evaluated. It is a literal list that contains various symbols and numbers, including assoc. There are two options here:
-
Use the backquote/comma mechanism of Lisp: the backquote is like quote except that when the quoted data contains a comma the expression after the comma is evaluated. You can imagine a template where some parts are fixed and other variables:
`((:tit ,(cdr (assoc :punctuacion libro)))) ...)Here above, the whole tree is quoted, except for the part that follows the comma. Note that you need to use
cdron the result ofassocto obtain the value, becauseassocreturns the entire entry, in other words the(key . value)couple. -
Only shadow the part of the value that changes:
(acons :score 0 libro)This is a purely functional approach where the
:scoreof zero is appended in front of the association list. The resulting structure is for example:((:score . 0) (:tit . 'Titulo1) (:aut . 'Autor1 ) (:gen . 'Genero1) (:score . 99))The next time you ask for the
:scorewithassoc, the first occurrence is obtained. If you are worried about having too many updates, you can also callremove:(acons :score 0 (remove :score libro :key #'car))This approach allows you to add keys without worrying about breaking existing code elsewhere.
Remarks
-
Please use readable names, like
:titleor:author -
Please format your code in a more conventional Lisp way
-
Be careful about how your data is organized:
(:score 40)The above is an association list from
:scoreto the singleton list(40). If you write instead(acons :score 40 nil)to build a proper association list, you will notice that this is printed as follows:(:score . 40)This is how a cons-cell whose
cdris not a list is printed. Generally speaking you want to call(cdr (assoc ...))to obtain the value, but if you don’t like having this dot in your data, then you have to take into account that your value,(cdr (assoc ...)), is a list: so if you have a convention that this value is always a list of a single element, then you have to call(car (cdr (assoc ...)))instead, also known as(cadr (assoc ...)).