Common Lisp 案例和引用的元素

问题描述 投票:0回答:1

我正在用 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 " "))))))))
common-lisp case quote
1个回答
14
投票

您不需要引用

CASE
中的符号。

实际上你不应该在

CASE
子句中引用符号。

看:这是错误的

CL-USER 31 > (case 'quote
               ('not-quote 'oops-really-quote)
               ('quote 'it-is-a-quote))
OOPS-REALLY-QUOTE

上面是使用

'not-quote
而不是正确的未引用的
not-quote
的意外结果。

下列说法正确的是:

CL-USER 32 > (case 'quote
               (not-quote 'oops-really-quote)
               (quote 'it-is-a-quote))
IT-IS-A-QUOTE

Common Lisp 中 CASE 的语法

case keyform
  {normal-clause}*
  [otherwise-clause]

=> result*

normal-clause::= (keys form*) 
otherwise-clause::= ({otherwise | t} form*) 
clause::= normal-clause | otherwise-clause 
keys ::= object | (object*)

如您所见,键要么是单个对象,要么是对象列表。不评估对象。

不评估 CASE 子句中的符号。

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

WALL
DOOR
纯粹是符号,不作为变量进行计算。

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 than 子句中使用
QUOTE
作为符号,因此编译器会显示警告。

正如我所说,无法报价,因为这些物品没有经过评估。

至于

CASE
接受子句中的项目列表,它看起来像这样:

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

对于

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

最好使用关键字符号,例如

:wall
。这样你就不需要导出它,并且不会混淆该符号位于哪个包中。

关于代码的格式: 您有一个项目符号列表,紧随其后的是代码部分。这不会按照您的预期呈现。我在代码之前添加了文本“代码:”。然后渲染就按预期工作了。

© www.soinside.com 2019 - 2024. All rights reserved.