В схеме, когда рекурсивная функция возвращает список, я не могу присвоить его переменной - PullRequest
3 голосов
/ 18 июля 2011

У меня есть следующий код:

(define (get-data)
  (define port (open-input-file "../data/problem11.txt"))
  (define field 0)
  (define (get-fields)
    (define field (read port))
    (cond ((not (eof-object? field)) 
           (cons field (get-fields)))  
          (else '())))

  (define returned (get-fields))
  (close-input-port port)
  returned)

(get-data)

Я не могу найти никаких проблем с моим кодом в соответствии с инструкциями, и в Google ничего не появляется при поиске, но когда я запускаю код, SCM (мой выбранный интерпретатор схемы) выдает мне следующую ошибку:

;ERROR: "/usr/lib/scm/Iedline.scm": unbound variable:  get-fields
; in expression: (get-fields)
; in scope:
;   (returned get-fields field port . #@define)
;   ()  procedure get-data
;STACK TRACE
1; (#@define ((returned (get-fields)) (get-fields (#@lambda () (# ...
2; (#@get-data)

Но когда я заставляю свой код выглядеть так, он отлично работает:

(define (get-data port)
  (define field 0)
  (define (get-fields)
    (define field (read port))
    (cond ((not (eof-object? field))
           (cons field (get-fields)))
          (else '())))
  (get-fields))


(define port (open-input-file "../data/problem11.txt"))
(define alfa (get-data port))
(close-input-port port)

Почему, когда я пытаюсь определить возвращенный как возвращенный список get-полей, я получаю ошибку несвязанной переменной, но когда я определяю alfa как возвращенный список get-данных (во втором блоке кода), это работает хорошо? Это то, что get-fields является рекурсивным? Я не понимаю Любые ответы здесь будут великолепны, спасибо.

1 Ответ

6 голосов
/ 19 июля 2011

Реализациям разрешено реализовывать внутренние define s, используя одну из двух возможных семантик: letrec и letrec*.

SCM явно выбрал использование letrec семантики. Это означает, что, учитывая набор внутренних define с, ни один из них не может сразу ссылаться на значение другого внутреннего define в той же группе: то же ограничение, что и letrec.

Некоторые реализации, такие как Racket, используют семантику letrec*. Это означает, что любая переменная, определенная в более раннем внутреннем define, может использоваться непосредственно более поздними внутренними define s. (Другими словами, ваш код будет отлично работать в любой реализации letrec*.)

Поскольку вы используете реализацию на основе letrec, сделайте следующее:

(let ((returned (get-fields)))
  (close-input-port port)
  returned)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...