无法设置列表的元素

时间:2014-11-07 23:24:07

标签: common-lisp

我在lisp非常新,我正在尝试制作一个基本的国际象棋游戏,但是我似乎在第一道障碍时失败了。每次我尝试运行函数(move... )时都会收到错误:

*** - FUNCTION: undefined function (SETF GET-ELEMENT)

以下是代码:

(defparameter *board* '(
                       (♜ ♞ ♝ ♛ ♚ ♝ ♞ ♜)
                       (♟ ♟ ♟ ♟ ♟ ♟ ♟ ♟)
                       (☐ ☐ ☐ ☐ ☐ ☐ ☐ ☐)
                       (☐ ☐ ☐ ☐ ☐ ☐ ☐ ☐)
                       (☐ ☐ ☐ ☐ ☐ ☐ ☐ ☐)
                       (☐ ☐ ☐ ☐ ☐ ☐ ☐ ☐)
                       (♙ ♙ ♙ ♙ ♙ ♙ ♙ ♙)
                       (♖ ♘ ♗ ♕ ♔ ♗ ♘ ♖)
                       ))

(defun print-rows (board)
  "Print each element of LIST on a line of its own."
  (mapcar #'print board))

(defun get-element (x y table)
  (nth x (nth y table)))

(defun move (x1 x2 y1 y2)
  (setf (get-element x2 y2 *board*) (get-element x1 y1 *board*)))

我很确定我对lisp有一个根本的误解,这就是为什么这不起作用,任何帮助都会非常感激。

1 个答案:

答案 0 :(得分:5)

不要修改文字数据

首先,当您将 * board * 定义为'(...)时,您已将其值设为文字对象。尝试修改文字数据的后果是未定义的,因此您需要避免这种情况。相反,将 * board * 定义为(copy-tree'(...))。这不是主要问题,但它是一个重要的问题。

(get-element ...)不是place

setf 的第一个(以及第三个,第五个等)参数是places。使用您当前的代码,(get-element ...)不是一个地方。定义并不严重(尽管对于随机二维访问,使用数组和 aref 可能更好)。你可以通过几种方式使(get-element ...)成为一个可以设置的地方。首先,您可以将 get-element 设为宏:

(defmacro get-element (x y table)
  `(nth ,x (nth ,y ,table)))

这是一个非常快速的解决方案,但它需要付出代价,因为现在你无法做出类似(map' get-element' (1 2)'(3 4)(制作清单2:初始元素表)),因为 get-element 不再是函数。一个更好的选择就是定义 setf 函数,通过利用(第n ...) 这个地方的事实来实现这个功能。可以与 setf

一起使用
(defun (setf get-element) (value x y table)
  (setf (nth x (nth y table)) value))

HyperSpec中描述了这种功能:

  

5.1.2.9 Other Compound Forms as Places

     

对于运算符为符号f的任何其他复合形式,   setf form扩展为对名为(setf f)的函数的调用。该   新构造的函数形式中的第一个参数是newvalue和   其余的参数是其余的元素。

这意味着(setf(get-element ...)值)会变成(funcall#'(setf get-element)值...),并且这正是我们刚刚定义的功能。

实施例

CL-USER> (defun (setf get-element) (value x y table)
           (setf (nth x (nth y table)) value))
; (SETF GET-ELEMENT)

CL-USER> (let ((board (copy-tree '((1 2 3)
                                   (4 5 6)))))
           (setf (get-element 1 1 board) 'x)
           board)
; ((1 2 3) (4 X 6))