【问题标题】:Lisp - "Trying to bind a non symbol" errorLisp - “尝试绑定非符号”错误
【发布时间】:2019-05-26 22:53:39
【问题描述】:

我是 Lisp 的新手,我正在为大学做一个项目。该项目是 LMC(小人计算机)的模拟。我有一个状态是事物列表(状态:ACC acc :PC pc :MEM mem :IN in :OUT out :FLAG 标志),“acc”“pc”和“flag”是值,“mem”“in " 和 "out" 是列表。

单指令将状态作为参数并应返回具有不同值的新状态,因为根据 (nth pc mem) 的结果,我必须执行某些操作。例如,如果 (nth pc mem) 的结果在 100 到 199 之间,我调用函数 do-add 应该为新状态的 acc 提供一个新值(还有一些尚未实现的控件)。

(defun one-instruction '(state:ACC acc :PC pc  :MEM mem :IN in :OUT out :FLAG flag)
    ((setf (nth pc mem) istruzione)
    (cond ( (0 < istruzione < 99) (do-halt '(state :ACC acc :PC pc :MEM mem :IN in :OUT out :FLAG flag))))
          ( (100 < istruzione < 199) (do-add '(state :ACC acc :PC pc :MEM mem :IN in :OUT out :FLAG flag)))))))
          ... 

(defun do-add '(state :ACC acc :PC pc  :MEM mem :IN in :OUT out :FLAG flag)))
   ((setf (nth pc mem) value)
   ((setf (nth (- value 100) mem) addendo)
   (setf (+ acc addendo) newacc))))

当我编译和加载时出现以下错误:

**++++单指令错误

尝试绑定非符号(状态:ACC acc :PC pc :MEM mem :IN in :OUT out :FLAG 标志),“do-add”也是如此。

所以我在两个函数中将状态作为参数传递的方式是错误的吗?或者也许我不能在没有 getf 的情况下使用“pc”和“mem”? 最后一个问题,我如何在一条指令中返回整个新状态并添加? 非常感谢! (抱歉英语不好,我是意大利人:))

【问题讨论】:

  • 我建议阅读Practical Common Lisp5. Functions 章节,了解定义函数参数的正确语法。 SETF 形式之前还有一些额外的括号(位置和值似乎也颠倒了),并且在 COND 测试中混合了一些中缀语法。

标签: lisp common-lisp


【解决方案1】:

DEFUN 的语法需要一个普通的 lambda 列表,它的最基本形式是一个未计算变量名列表。您的代码开头如下:

(defun one-instruction '(state:ACC acc :PC pc  :MEM mem :IN in :OUT out :FLAG flag)
   ...)

您有两个主要错误:

  • 你引用了列表
  • 您的 lambda 列表格式不正确

试图绑定一个非符号,(state:ACC acc :PC pc :MEM mem :IN in :OUT out :FLAG flag)

这个错误有点奇怪,但请记住'(a b c) 代表(quote (a b c)),在defun 的上下文中,lambda-list 被解析为一个二元素列表quote 和@ 987654330@ 名单。第二个列表不是符号,这就是在您的情况下检测到格式错误的 lambda 列表的方式。

:pc pc 语法用于传递关键字参数,而不是在函数中绑定它们。如果你想用一个强制的状态变量和关键字参数正确定义你的函数,你应该写:

(defun one-instruction (state &key acc pc mem in out flag)
  ...)

你可以这样称呼它:

(one-instruction my-state :acc 0 :pc 0 :mem big-table ...)

另外,你有:

((setf (nth pc mem) istruzione) ...)

这不是一个有效的表达式,表达式看起来像(x ...),其中xsetf 表达式;但是(x ...) 在正常的评估上下文中意味着函数调用,而(setf ...) 不是函数。


在:(setf (nth pc mem) value) 我想绑定 (nth pc mem) 的结果,如果我是正确的,它应该给我列表“mem”中的值将“pc”定位到变量“value”

您不使用setf 引入变量,它只会修改现有绑定(更一般地说,位置)。相反,你必须使用LET:

(let ((instruction (nth n mem)))
  ...)

... 内部,instruction 绑定到通过评估(nth n mem) 获得的值。

另请注意,cond 表达式中的测试表达式也是格式错误的:

(0 < istruzione < 99)

上面的内容是:调用函数0,参数为;没有名为0 的函数,并且&lt; 未绑定为变量。你想要的是:

(< 0 istruzione 99)

以上是对&lt;的多参数调用,当所有值都按照&lt;排序时为真。

还要注意,在下一个测试中,您有 100 &lt; istruzione,这意味着 99 和 100 都是您的 cond 无法处理的极端情况(除非是故意的,在这种情况下很好)。

【讨论】:

  • 非常感谢,这真的很有帮助。因此,当我定义函数时,我只需要编写 (state &key x1 x2..),然后仅当我调用时才使用 (:acc 0 pc:0 ..) 之类的关键字参数?对于setf问题,老师给出了将nth和setf结合起来的建议。在:(setf(nth pc mem)值)我想绑定(nth pc mem)的结果,如果我是正确的,它应该在位置“pc”处给我列表“mem”中的值”,到变量“值”。所以不可能以这种方式做到这一点?再次感谢您!
  • @Elia 谢谢。您必须改用 LET,请参阅编辑。
  • 非常感谢,现在一切都清楚了!今晚我将尝试用所有这些信息重写项目!那么老师给出的使用 setf 结合 nth 的建议不适合这种情况吗?或者,也许我必须使用“do-add”中的 setf 来更改新状态的“acc”值,之后我执行了两个 (let((value(nth ...))) 和 (let(( addendo(nth...))) 喜欢 (setf acc (+ acc addendo))?
猜你喜欢
  • 1970-01-01
  • 2011-08-03
  • 1970-01-01
  • 1970-01-01
  • 2015-12-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多