Common Lisp case和引用元素

时间:2011-04-01 07:23:29

标签: common-lisp case quote

我正在用CL写一个地牢爬虫游戏,我遇到了案例表格的问题。

两件事:

  • Common Lisp抱怨Duplicate keyform QUOTE in CASE statement
  • (make-instance 'cl-rogue:tile tile-type 'wall)应打印为“#”,但无论我使用哪种图块类型,对象都会打印为“”。

代码:

(in-package :cl-user)

(defpackage :cl-rogue
  (:use :common-lisp)
  (:export
    :*rows*
    :*cols*
    :*levels*
    :tile
    :tile-type
    :tile-contents
    :tile-hidden
    :tile-locked
    :tile-closed
    :main))

(in-package :cl-rogue)

(defparameter *cols* 80)
(defparameter *rows* 24)
(defparameter *levels* 26)

班级:

(defclass tile ()
  ((tile-type
    :initarg :tile-type
    :accessor tile-type
    :initform 'floor
    :documentation "Type of tile")
    (tile-contents
      :initarg :tile-contents
      :accessor tile-contents
      :initform '()
      :documentation "Any items the tile holds")
    (tile-hidden
      :initarg :tile-hidden
      :accessor tile-hidden
      :initform nil
      :documentation "Whether the tile is hidden or shown")
    (tile-locked
      :initarg :tile-locked
      :accessor tile-locked
      :initform nil
      :documentation "Whether the tile is locked")
    (tile-closed
      :initarg :tile-closed
      :accessor tile-closed
      :initform nil
      :documentation "Whether the tile is open or closed")))

打印方法:

(defmethod print-object ((object tile) stream)
  (with-slots (tile-type tile-contents tile-hidden tile-locked tile-closed) object
    (if tile-hidden
      (format stream " ")
      (let ((an-item (car tile-contents)))
        (if an-item
          (format stream "~a" an-item)
          (format stream (case tile-type
            ('wall "#")
            ('upstair "<")
            ('downstair ">")
            ('door (if tile-closed "+" "\\"))
            (otherwise " "))))))))

1 个答案:

答案 0 :(得分:11)

您无需引用CASE中的符号。

不评估CASE子句中的符号。

(case tile-type
  (wall ...)
  (door ...))

WALLDOOR纯粹是符号,不会被评估为变量。

Lisp读者将'foo读为(quote foo)

您写道:

(case tile-type
  ('wall ...)
  ('door ...))

相当于:

(case tile-type
  ((quote wall) ...)
  ((quote door) ...))

但你不能引用CASE中的符号。您必须将符号作为文字常量提供。

如果你写:

(let ((bar 'foo)
      (baz 'foo))
  (case bar
    (baz :we-have-a-foo-through-baz)
    (foo :we-really-have-a-foo)))

返回:WE-REALLY-HAVE-A-FOO。因为CASE使用常量数据,而不是变量。

CASE接受一个项目列表。由于您在more子句中有QUOTE作为符号,因此编译器显示警告。

正如我所说,没有引用可能,因为不评估项目。

至于CASE接受条款中的项目列表,它看起来像这样:

(case tile-type
  ((door wall) ...)
  ((floor window painting) ...))

对于WALL符号,您需要确保在创建对象时它位于正确的包中。

最好使用关键字符号,例如:wall。然后你不需要导出它,并且没有关于符号在哪个包中的混淆。

关于代码的格式: 你有一个子弹列表,紧接着是代码部分。这不会像您期望的那样呈现。我在代码之前添加了文本'The code:'。然后渲染按预期工作。