【问题标题】:Illegal Function Call in Common LispCommon Lisp 中的非法函数调用
【发布时间】:2010-10-30 00:18:42
【问题描述】:

我正在制作一款两人井字游戏,目前正处于解决代码中所有错误的阶段。我遇到的当前错误是以下代码中的illegal function call 错误:

(cond

[...snip...]

((= CHOICE 3)
 (IF (NUMBERP (AREF *BOARD* 0 2))
     (SETF (AREF *BOARD* 0 2) *MARKER*)
     (INVALID-SELECTION)))

我做错了什么?

EDIT 整个函数如下所示:

(defun select (choice)
    (cond ((= choice 1)
               (if (numberp (aref *board* 0 0)) (setf (aref *board* 0 0) *marker*)
                                                (invalid-selection))))
                ((= choice 2)
               (if (numberp (aref *board* 0 1)) (setf (aref *board* 0 1) *marker*)
                                                (invalid-selection))))
              ((= choice 3)
               (if (numberp (aref *board* 0 2)) (setf (aref *board* 0 2) *marker*)
                                                (invalid-selection))))
              ((= choice 4)
               (if (numberp (aref *board* 1 0)) (setf (aref *board* 1 0) *marker*)
                                                (invalid-selection))))
              ((= choice 5)
               (if (numberp (aref *board* 1 1)) (setf (aref *board* 1 1) *marker*)
                                                (invalid-selection))))
              ((= choice 6)
               (if (numberp (aref *board* 1 2)) (setf (aref *board* 1 2) *marker*)
                                                (invalid-selection))))
              ((= choice 7)
               (if (numberp (aref *board* 2 0)) (setf (aref *board* 2 0) *marker*)
                                                (invalid-selection))))
              ((= choice 8)
               (if (numberp (aref *board* 2 1)) (setf (aref *board* 2 1) *marker*)
                                                (invalid-selection))))
              ((= choice 9)
               (if (numberp (aref *board* 2 2)) (setf (aref *board* 2 2) *marker*)
                                                (invalid-selection))))

【问题讨论】:

    标签: lisp common-lisp sbcl


    【解决方案1】:

    你的函数看起来只是这样,只是因为它没有正确缩进。

    选择代码并缩进该区域 - 任何懂一点 Lisp 的编辑器都应该为您做这件事。在 LispWorks 中,这是通过扩展编辑器命令“缩进区域”完成的。

    您也可以将 COND 替换为更简单的 CASE:

    (case choice
      (1 ...)
      (2 ...))
    

    使用 CASE 和局部函数可以使整个函数变小:

    (defun select (choice)
      (flet ((do-something (x y)
               (if (numberp (aref *board* x y))
                   (setf (aref *board* x y) *marker*)
                 (invalid-selection))))
        (case choice
          (1 (do-something 0 0))
          (2 (do-something 0 1))
          (3 (do-something 0 2))
          (4 (do-something 1 0))
          (5 (do-something 1 1))
          (6 (do-something 1 2))
          (7 (do-something 2 0))
          (8 (do-something 2 1))
          (9 (do-something 2 2)))))
    

    【讨论】:

    • 我的函数的缩进与显示的不同,这就是我将它粘贴到页面上时的结果:/
    【解决方案2】:

    正常求值形式中的第一件事几乎总是一个符号,用于命名函数、宏或特殊运算符。表单中的第一件事是列表(= CHOICE 3)。更多的上下文会有所帮助;正如 Cirno 所说,这看起来像是一个没有实体的 COND 子句。

    edit 我将您的代码放在一个函数中,并添加了足够的括号和变量定义来评估它,它的评估结果很好。仍然需要更多上下文。

    【讨论】:

      【解决方案3】:

      我想通了!由于复制+粘贴技能不佳,我的函数中的括号过多。

      【讨论】:

      • 那应该教你。切勿使用复制/粘贴。在这种情况下,您可以使用(let ((x (floor choice 3)) (y (rem choice 3))) (if (numberp (aref *board* x y)) (setf (aref *board* x y) *marker*) (invalid-selection))),而不是长的cond。在其他情况下,将重复的代码分解为函数或宏。
      • 如果你知道多个值是什么,你也可以直接使用floor函数的两个返回值:(multiple-value-bind (x y) (floor choice 3) (if ...))
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-09-23
      • 2014-11-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多