如何在 LISP 中使用循环

Tim*_*yer 3 lisp list 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)))
Run Code Online (Sandbox Code Playgroud)

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

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

jki*_*ski 5

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

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

    (loop for...
          when (eq ...) do (return-from ...))
    
    Run Code Online (Sandbox Code Playgroud)
  2. WHEN在循环子句中使用常规的-macro DO

    (loop for...
          do (when (eq ...)
               (return-from ...)))
    
    Run Code Online (Sandbox Code Playgroud)

您的代码中还有一些其他问题需要修复。

  1. 在 Lisp 中命名时,在单词之间使用破折号而不是驼峰命名(check-zero而不是checkZero)。
  2. 使用=一般的数字比较,或者ZEROP检查一个数字是零。EQ用于检查两个对象是否是同一个对象。
  3. 您可以使用从循环返回 RETURN
  4. 我不太确定你想用 完成什么(VALUES-LIST (NTH ... (CAR ...))),但它不会起作用。如果您想简单地循环遍历值的平面列表(例如(1 2 3 4 5 6)),则应该使用循环FOR item IN list子句。

所以现在你应该有类似的东西:

(defun check-zero (list)
  (loop for item in list
        when (zerop item) do (return t)))
Run Code Online (Sandbox Code Playgroud)

LOOP还有一个THEREIS condition-clause 可以使用:

(defun check-zero (list)
  (loop for item in list
        thereis (zerop item)))
Run Code Online (Sandbox Code Playgroud)

一旦找到满足 的项目,就会返回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)
Run Code Online (Sandbox Code Playgroud)

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

由于有一个谓词函数 ( 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)
Run Code Online (Sandbox Code Playgroud)