lisp和do构造中存在的问题

lisp和do构造中存在的问题,lisp,common-lisp,Lisp,Common Lisp,首先,我有这个问题。我生成的代码不是遍历每个单词,而是遍历整个传递的参数。我使用do循环将信息传递到哈希表中 (defun set_isa (partOfSpeech &rest words) (do ((wordVar words)) ((null wordVar) nil) (putp partOfSpeech word-dict wordVar) (setf wordVar (cdr wordVar)))) 有了这个,我就可以用trace得到这个结果 (set_isa 'V

首先,我有这个问题。我生成的代码不是遍历每个单词,而是遍历整个传递的参数。我使用do循环将信息传递到哈希表中

(defun set_isa (partOfSpeech &rest words)

(do ((wordVar words))
((null wordVar) nil) 

(putp partOfSpeech word-dict wordVar)
(setf wordVar (cdr wordVar))))
有了这个,我就可以用trace得到这个结果

(set_isa 'Verb 'Talk 'Run 'jump )

1. Trace: (SET_ISA 'VERB 'TALK 'RUN 'JUMP)
1. Trace: SET_ISA ==> NIL
NIL
当我调用哈希表时,它只添加最后传递的参数

#S(HASH-TABLE :TEST FASTHASH-EQL (VERB . (JUMP)))

欢迎来到SO。我发现我们的问题有一些问题,希望我能给你一些提示

压痕 请正确缩进代码。这将导致更可读的代码,并将增加其他人可以帮助您的可能性

(defun set_isa (partOfSpeech &rest words)
  "Put an understandable docstring here!"
  (do ((wordVar words))
      ((null wordVar) nil) 
    (putp partOfSpeech word-dict wordVar)
    (setf wordVar (cdr wordVar))))
你会发现更多关于风格的建议。有关参考的集合,请参见

可运行示例 在我们的函数中,
putp
没有定义。因此,我无法运行您的代码,也无法查看要准确获取的错误,等等。请始终提供完整的示例,并清楚地描述您的期望和获得的结果。包含
哈希表的部分根本不清楚。它来自哪里?它在我们的代码中是如何使用的

做循环 查看初学者参考资料,了解
do
及其相关词的正确语法。如果要使用
do
遍历列表,请尝试
dolist

(dolist (item '(a b c d))
  (print item))
使用
do
您可以通过此构造实现相同的效果:

(do ((items '(a b c d) (rest items)))
    ((null items))
  (print (first items)))

首先,我可能会觉得很难把括号弄对,但是如果你把它背后的逻辑弄对了,它会变得更容易。您不需要
setf
部分,因为
do
将处理它。

欢迎使用。我发现我们的问题有一些问题,希望我能给你一些提示

压痕 请正确缩进代码。这将导致更可读的代码,并将增加其他人可以帮助您的可能性

(defun set_isa (partOfSpeech &rest words)
  "Put an understandable docstring here!"
  (do ((wordVar words))
      ((null wordVar) nil) 
    (putp partOfSpeech word-dict wordVar)
    (setf wordVar (cdr wordVar))))
你会发现更多关于风格的建议。有关参考的集合,请参见

可运行示例 在我们的函数中,
putp
没有定义。因此,我无法运行您的代码,也无法查看要准确获取的错误,等等。请始终提供完整的示例,并清楚地描述您的期望和获得的结果。包含
哈希表的部分根本不清楚。它来自哪里?它在我们的代码中是如何使用的

做循环 查看初学者参考资料,了解
do
及其相关词的正确语法。如果要使用
do
遍历列表,请尝试
dolist

(dolist (item '(a b c d))
  (print item))
使用
do
您可以通过此构造实现相同的效果:

(do ((items '(a b c d) (rest items)))
    ((null items))
  (print (first items)))

首先,我可能会觉得很难把括号弄对,但是如果你把它背后的逻辑弄对了,它会变得更容易。您不需要
setf
部分,因为
do
会处理它。

因此,理解这里发生的事情的方法是对代码进行注释,以便它告诉您它在做什么。这似乎是一种古老的调试方式,但在像CL这样的动态对话语言中,这是一种非常好的方法。这是一个函数的版本,它对事物使用了更为传统的名称,还使用了传统的索引,并为丢失的代码添加了存根,使其能够运行

(defvar *word-dict* nil)

(defun set-isa (part-of-speech &rest words)
  (do ((wtail words))
      ((null wtail) nil) 
    (putp part-of-speech *word-dict* wtail)
    (setf wtail (cdr wtail))))

(defun putp (part-of-speech dict thing)
  (format *debug-io* "~&putp: ~A ~A ~A~%" part-of-speech dict thing))
现在这是可运行的,
putp
将把它得到的作为参数打印出来

 > (set-isa 'verb 'talk 'run 'jump )
putp: verb nil (talk run jump)
putp: verb nil (run jump)
putp: verb nil (jump)
nil
因此,即使这里没有实际存在错误的代码,这几乎肯定是
putp
,您也可以找出问题所在:
putp
用它的参数替换哈希表中存储的任何值。因此,表中唯一的值是最后一个。所以我们需要解决这个问题,我稍后会做

但事实上,这不是唯一的问题

首先,你用了一种非常奇怪的方式使用
do
do
的语法明确允许初始化和步进形式,因此实际上应该使用步进形式,而不是在正文中使用

(defun set-isa (part-of-speech &rest words)
  (do ((wtail words (rest wtail)))
      ((null wtail) nil) 
    (putp part-of-speech *word-dict* wtail)))
其次,你在列表的所有尾部调用
putp
:你可能只想在单个单词上调用它。您可以通过简单地将每个尾部的car传递给它来实现这一点,但是正如Martin Buchmann在另一个答案中指出的那样,您可以在语言中寻找一个迭代列表元素的构造。有很多这样的例子,
dolist
就是其中之一:

(defun set-isa (part-of-speech &rest words)
  (dolist (word words)
    (putp part-of-speech *word-dict* word)))
现在呢

(set-isa 'verb 'talk 'run 'jump )
putp: verb nil talk
putp: verb nil run
putp: verb nil jump
nil
请注意,
putp
的调用方式与以前的版本不兼容:现在在单词上调用它,而不是在列表的尾部

最后,让我们编写一个有效的
putp
。我将首先编写一个非常简单的版本:

(defvar *word-dict* (make-hash-table))

(defun putp (part-of-speech dict thing)
  (let ((entries (gethash part-of-speech dict '())))
    (setf (gethash part-of-speech dict) (cons thing entries))))
这是可行的,但不是很好:

> (gethash 'verb *word-dict* '())
nil
nil

> (set-isa 'verb 'talk 'run 'jump )
nil

> (gethash 'verb *word-dict* '())
(jump run talk)
t

> (set-isa 'verb 'talk 'run 'jump )
nil

> (gethash 'verb *word-dict* '())
(jump run talk jump run talk)
t
没关系,只要你只运行一次。好吧,我们可以做得更好:

  • 我们可以使用更惯用的方式将新事物推送到哈希表中存储的列表上
  • 我们可以避免重复条目的事情,同时也更加习惯
像这样:

(defun putp (part-of-speech dict thing)
  (pushnew thing (gethash part-of-speech dict)))
所以,现在:

 > (gethash 'verb *word-dict* '())
nil
nil

> (set-isa 'verb 'talk 'run 'jump )
nil

> (gethash 'verb *word-dict* '())
(jump run talk)
t

> (set-isa 'verb 'talk 'run 'jump )
nil

> (gethash 'verb *word-dict* '())
(jump run talk)

这样好多了。您可以查看
push
,以及
pushnew
,查看它们的功能。

因此,理解这里发生的事情的方法是对代码进行注释,以便它告诉您它在做什么。这似乎是一种古老的调试方式,但在像CL这样的动态对话语言中,这是一种非常好的方法。这是一个函数的版本,它对事物使用了更为传统的名称,还使用了传统的索引,并为丢失的代码添加了存根,使其能够运行

(defvar *word-dict* nil)

(defun set-isa (part-of-speech &rest words)
  (do ((wtail words))
      ((null wtail) nil) 
    (putp part-of-speech *word-dict* wtail)
    (setf wtail (cdr wtail))))

(defun putp (part-of-speech dict thing)
  (format *debug-io* "~&putp: ~A ~A ~A~%" part-of-speech dict thing))
现在这是可运行的,
putp
将把它得到的作为参数打印出来

 > (set-isa 'verb 'talk 'run 'jump )
putp: verb nil (talk run jump)
putp: verb nil (run jump)
putp: verb nil (jump)
nil
因此,即使这里没有实际存在错误的代码,这几乎肯定是
putp
,您也可以找出问题所在:
putp
用它的参数替换哈希表中存储的任何值。因此,表中唯一的值是最后一个。所以我们需要解决这个问题,我稍后会做

但事实上,这不是唯一的问题

首先