clisp:无法从列表中搜索

clisp: unable to search from a list

昨晚开始学习LISP,目前正在用普通LISP编写一个基于文本的酒店客房预订系统。这些是我初始化列表和变量的行:

(defparameter *rooms* (list 0))
(defvar counter 0)
(defvar room-num 0)

以下是我操纵这些代码来搜索我的列表的代码片段:

(loop
(setq room-num(read))
    (if (and 
            (> counter 0)(equal t (find room-num '(*room*)))
        )
        (progn 
           (print "Room already exists:")
           (return 1)
        )
    )
(push room-num (cdr (last *rooms*)))
(setq counter (+ counter 1))
)

如果列表中尚不存在房间号,则以上代码会将房间号附加到房间列表中。 我遇到的问题是在房间列表中找到房间号。

以下是我尝试过的方法(如果代码很草率,抱歉。正如我所说,我昨天才开始使用 LISP):

(if (and (> counter 0)(equal  (member room-num *room*)))

也尝试过:

(if ((if (member room-num '(rooms)) t nil))
        (print "Room already exists")
    )

如有任何帮助,我们将不胜感激。

这个声明没问题:

(defparameter *rooms* (list 0))

以下几个不太好:

(defvar counter 0)
(defvar room-num 0)

defvar声明的特殊变量应该用earmuffs命名,即。一对星号,就像您对前一个变量所做的那样。 阅读代码时知道某些变量是全局变量会很有帮助。

此外,您正在编写一个操纵全局状态的脚本,而不是定义一个只修改局部状态的函数。对于一个小例子,这没问题,但一个很好的练习是将这个脚本封装在一个函数中。

(loop
(setq room-num(read))
    (if (and
            (> counter 0)(equal t (find room-num '(*room*)))
        )
        (progn
           (print "Room already exists:")
           (return 1)
        )
    )
(push room-num (cdr (last *rooms*)))
(setq counter (+ counter 1))
)

格式不规范,请遵照an idiomatic style。 这是您重新格式化的代码:

(loop
   (setq room-num (read))
   (when (and (> counter 0)
              (equal t (find room-num '(*room*))))
     (print "Room already exists:")
     (return 1))
   (push room-num (cdr (last *rooms*)))
   (setq counter (+ counter 1)))

我用(when A B C)替换了(if A (progn B C)),这样更易​​读。

现在,你的问题在这里:

 (equal t (find room-num '(*room*)))

您正试图在 列表中查找 room-num,该列表字面上包含符号 *room*,而不是名为 [=21 的变量的值=]. 这是因为你引用了列表:'(*room*)(quote (*room*)) 相同,当评估时 return Lisp reader 读取的形式,即一个列表符号。

你只需要调用(member room-num *room*)来测试成员资格,你不必比较(member ...)t的return值,使用(equal t ...):如果测试成功,它将是非空的,即。是的。

还有:

(push room-num (cdr (last *rooms*)))

你不需要将房间作为最后一个元素推入,只需将其放在前面:

(push room *rooms*)

顺序在您的情况下无关紧要,并且您可以使用 last.

避免遍历列表。

此外,除了@coredump 的回答之外,您还可以使用一些现有的常见 lisp 工具,例如(使用 loop 宏):

(loop for counter from 0
      for room = (read)
      until (find room rooms)
      collect room into rooms
      finally (progn (format t "room ~a already exists in ~a~%" room rooms)
                     (return (values rooms counter))))

或这个(使用do):

(let ((rooms))
  (do ((counter 0 (1+ counter))
       (room (read) (read)))
      ((find room rooms)
       (format t "room ~a already exists in ~a~%" room rooms)
       (values rooms counter))
    (push room rooms)))

虽然这不是答案,但使用高级工具解决问题可以节省大量调试时间。