如何在LISP中使用循环

时间:2016-10-05 04:49:19

标签: list lisp common-lisp

我一直在努力了解如何在LISP中使用循环,但它们似乎仍然无法正常工作。我尝试使用以下代码:

    (loop for i from 0 to (list-length y)
          (when (eq (values-list (nth i (car y))) 0)
             (return-from checkZero t)))

哪个应循环检查我的列表,检查我的值是否等于0。如果它相等则它应该从循环返回并退出循环,否则它应该运行直到它达到列表长度。我在考虑这个错误,如果是这样,我该如何解决这个问题呢?

(我不确定我的实际代码是否有效,因为我仍在处理由错误使用的循环生成的错误,我找不到很多在线使用循环的好资源)

1 个答案:

答案 0 :(得分:4)

循环中的主要问题是WHEN - 表达式。有两种方法可以写出来:

  1. 使用循环WHEN condition DO forms - 子句:

    (loop for...
          when (eq ...) do (return-from ...))
    
  2. 在循环WHEN中使用常规DO - 宏 - 子句:

    (loop for...
          do (when (eq ...)
               (return-from ...)))
    
  3. 您的代码中还有一些其他问题需要解决。

    1. 在Lisp中命名时,在单词之间使用短划线而不是camelCase(check-zero而不是checkZero)。
    2. 使用=进行常规数字比较,或使用ZEROP检查数字是否为零。 EQ用于检查两个对象是否是同一个对象。
    3. 您可以使用RETURN
    4. 从循环返回
    5. 我不太确定您使用(VALUES-LIST (NTH ... (CAR ...)))尝试完成的任务,但它无法正常工作。如果您试图简单地循环遍历一个平坦的值列表(例如(1 2 3 4 5 6)),那么您应该使用循环FOR item IN list - 子句。
    6. 所以现在你应该有类似的东西:

      (defun check-zero (list)
        (loop for item in list
              when (zerop item) do (return t)))
      

      LOOP还有一个THEREIS condition - 您可以使用的子句:

      (defun check-zero (list)
        (loop for item in list
              thereis (zerop item)))
      

      一旦找到满足ZEROP的项目,就立即返回。但是,有更简单的方法来实现同样的目标。您可以使用MEMBER检查列表是否包含零:

      (defun check-zero (list)
        (member 0 list :test #'=))
      
      CL-USER> (check-zero '(1 3 4 3 5 7))
      NIL
      CL-USER> (check-zero '(1 3 4 3 0 5 7))
      (0 5 7)
      

      返回一个广义布尔值。也就是说,在Common Lisp中,任何不是NIL的值都被认为是真的。

      由于存在谓词函数(ZEROP)来检查对象是否为零,因此您还可以使用SOMEMEMBER-IF

      (some #'zerop '(1 3 4 6 2 0 45 6 7)) ;=> T
      (member-if #'zerop '(1 3 4 6 2 0 45 6 7)) ;=> (0 45 6 7)