Всегда получаю «RETURN-FROM: ни один блок с именем NIL в настоящее время не виден» - PullRequest
1 голос
/ 30 октября 2019
(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 ]

7 голосов
/ 30 октября 2019
  1. Пожалуйста, сделайте отступ в коде на Лиспе (это можно сделать автоматически во многих редакторах, например, в 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), но, пожалуйста, не используйте слишком сокращенные имена;например, вы можете использовать list и new-list.

  4. return возвращает возвращаемый блок с именем nil, но здесь у вас такого блока нет. Вместо этого defun вводит неявный блок, названный как функция, которую вы определяете, то есть у вас есть неявно:

    (block take-n
      ...)
    

    Так что, если вы хотите вернуться из него, вам нужно будет сделать (return-from take-n newlst).

  5. НО, вам не нужно возвращаться, так как последняя форма, вычисляемая в функции, является значением, связанным с вызовом функции в любом случае.

5 голосов
/ 30 октября 2019

Вам не нужно использовать RETURN. В Лиспе последнее выражение в теле функции возвращается автоматически, поэтому просто поместите переменную в конец функции. Кроме того, вам следует связать локальную переменную с 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.

...