【问题标题】:clisp: unable to search from a listclisp:无法从列表中搜索
【发布时间】:2020-04-17 12:16:19
【问题描述】:

我昨晚开始学习 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")
    )

任何帮助将不胜感激。

【问题讨论】:

    标签: lisp common-lisp


    【解决方案1】:

    此外,除了@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)))
    

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

    【讨论】:

      【解决方案2】:

      这个声明很好:

      (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)))
      

      我将(if A (progn B C))替换为(when A B C),这样更容易阅读。

      现在,你的问题来了:

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

      您试图在包含符号*room* 的列表中查找room-num,而不是名为*room* 的变量的值。 这是因为您引用了列表:'(*room*)(quote (*room*)) 相同,后者在评估时仅返回 Lisp 阅读器读取的形式,即一个符号的列表。

      你只需要调用(member room-num *room*)来测试成员资格,你不必比较(member ...)t的返回值,使用(equal t ...):如果测试成功,则为非空, IE。真的。

      还有:

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

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

      (push room *rooms*)
      

      无论如何,顺序在您的情况下并不重要,并且您可以避免使用last 对列表进行一次遍历。

      【讨论】:

      • 非常感谢。你救了我的命。我一直试图让那个搜索条件工作很长时间。这很容易,但我无法弄清楚。如果没有你的帮助,我不会这样做。
      • 也感谢您告诉我的传统格式化方式。顺便说一句,我没有在此处发布的其余代码取决于房间列表。所以我不能把它推到前面。我需要附加它们。这就是为什么我最后使用 push 的原因。
      • @VeryBhatti -- “我没有在此处发布的其余代码取决于房间列表”:您可能会重新考虑是否真的需要或想要其他功能取决于房间列表的特定顺序。这听起来很脆弱且容易出错;您可以在需要这样的事情时以所需的方式对列表进行排序。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-08-22
      • 2020-11-21
      • 1970-01-01
      • 2018-12-19
      • 2022-01-17
      • 2019-05-27
      • 2017-05-18
      相关资源
      最近更新 更多