Lisp中Lambda内assoc未求值:如何用mapcar重置书籍分数为0
LISP中使用mapcar和lambda重置书籍score的问题
数据结构定义
用户定义了如下书籍列表数据结构:
(setf *books* '( ( (:tit 'Titulo1) (:aut (quote Autor1)) (:gen 'Genero1) (:score 99) ) ( (:tit 'Titulo2) (:aut (quote Autor2)) (:gen 'Genero2) (:score 40) ) ))
需求与问题代码
需求是通过mapcar和lambda将所有书籍的score字段重置为0,用户尝试编写的reset函数如下:
(defun reset(list) (mapcar (lambda(libro) '( (:tit (assoc :puntuacion libro)) (:aut (assoc :aut libro)) (:gen (assoc :gen libro)) (:score 0) ) ) list ) )
这段代码的核心问题:
- 用单引号
'包裹返回列表,导致列表内所有表达式都被当作字面量,assoc函数完全不会被求值,直接返回符号本身。 - 错误使用
:puntuacion作为键,原数据结构中对应的键是:tit。 - 即便
assoc被求值,它返回的是完整键值对(如(:tit 'Titulo1)),而非对应的值,需要额外提取值部分。
正确实现方式
使用**反引号`**构建模板列表,配合逗号,插入求值结果,同时修正键名并提取assoc返回的值:
(defun reset (book-list) (mapcar (lambda (libro) `((:tit ,(cadr (assoc :tit libro))) (:aut ,(cadr (assoc :aut libro))) (:gen ,(cadr (assoc :gen libro))) (:score 0))) book-list))
代码说明:
- 反引号
`创建模板列表,普通元素保持字面量,逗号,后的表达式会被求值并插入列表。 (assoc :tit libro)找到单本书籍中:tit对应的键值对,cadr用于取出该键对应的值(如'Titulo1)。- 修正键名错误,将
:puntuacion改为:tit,匹配原数据结构的字段。
调用(reset *books*)会返回所有score重置为0的新书籍列表,原*books*列表不会被修改(LISP列表默认不可变,mapcar返回新列表)。
内容的提问来源于stack exchange,提问作者Jose A. Matarán
相关产品推荐
相关产品推荐

