总是得到“ RETURN-FROM:当前看不到名为NIL的块”

时间:2019-10-30 16:40:30

标签: functional-programming lisp common-lisp

(defun take-n (lst i)
  (setf newlst '())    
  (dotimes (n i)
    (setf newlst (cons (car lst) newlst))
    (print (cons (car lst) newlst))
    (setf lst (cdr lst)))
  (return newlst))
(print (take-n '(1 2 3) 2))

这给我一个RETURN-FROM错误:当前看不到名为NIL的块。我已经尝试过将return语句移走,但是我不确定它的含义。

2 个答案:

答案 0 :(得分:7)

  1. 请以Lisp方式缩进代码(可以在许多编辑器(例如Emacs)中自动完成):

    (defun take-n (lst i)
      (setf newlst '())
      (dotimes (n i)
        (setf newlst (cons (car lst) newlst))
        (print (cons (car lst) newlst))
        (setf lst (cdr lst)))
      (return newlst))
    
    (print (take-n '(1 2 3) 2))
    
  2. 不要setf事先未声明的变量:(setf newlst '())指的是假设的全局变量newlst,但是在函数中,您应该努力只具有局部变量州。您可以使用let在块中引入变量,如下所示:

    (let ((new-list ()))
      ...
      ;; here you can setf new-list if you need
      ...)
    
  3. (setf newlst (cons (car lst) newlst))也可以写成(push (car lst) newlst),但是请不要使用过分缩写的名称。例如,您可以使用listnew-list

  4. return返回到名为nil的封闭块,但是这里没有这样的块。相反,defun引入了一个隐式块,其名称类似于您定义的函数,即您隐式地:

    (block take-n
      ...)
    

    因此,如果您想从中返回,则需要执行(return-from take-n newlst)

  5. 但是,您不需要返回,因为该函数中最后一个要求值的形式仍然是与该函数调用关联的值。

答案 1 :(得分:5)

您不需要使用RETURN。在Lisp中,函数主体中的最后一个表达式是自动返回的,因此只需将变量放在函数的末尾即可。另外,您应将本地变量与LET绑定,而不要分配全局变量。

(defun take-n (lst i)
  (let ((newlist '()))
    (dotimes (n i)
      (setf newlst (cons (car lst) newlst))
      (print (cons (car lst) newlst))
      (setf lst (cdr lst)))
    newlst))

您得到的错误是因为DEFUN在函数体周围放置了一个命名块,因此您需要使用(return-from take-n newlst)return仅可用于从未命名的块(名称为NIL的块)返回;这些会自动放在DO之类的循环宏周围。