Небольшой вопрос о схеме - PullRequest
4 голосов
/ 14 сентября 2010

Я очень плохо знаком с LISP, и недавно я обнаружил тонкий, который я не понимаю.

Этот код работает:

(define (f x) (define a x) (define (b) a) (b))

А это не так:

(define (f x) (define a x) (define b a) b)

Почему?

Ответы [ 3 ]

2 голосов
/ 14 сентября 2010

Вам следует поискать обсуждения о letrec* - некоторые реализации используют его как более строгую версию более строгого letrec, что приводит к разнице, которую вы видите.

2 голосов
/ 14 сентября 2010

В Kawa Interpeter это работает В Guile это не так, потому что этот код

(define (f x) (define a x) (define b a) b)

расширен до

(define (f x) (letrec ((a x) (b a)) b))

И вы не можете получить доступ к a раньшеЯ назначаю.letrec не будет работать для не функциональных определений, например:

(letrec ((x 5)
         (y x))
     y)

Вы можете использовать let* insted

(define (f x) (let* ((a x) (b a)) b))

В этом коде

(define (f x) (define a x) (define (b) a) (b))

В процедуре b вы получаете доступ к переменной, когда она уже определена.

0 голосов
/ 29 апреля 2012

Возможно, вы видите изменение в поведении между стандартами R5RS и R6RS. Одним из изменений в R6RS является «Внутренние определения теперь определяются в терминах letrec*».

В R5RS внутренние define с полностью эквивалентны letrec. В частности, в разделе о внутренних определениях говорится, что «Как и в случае эквивалентного letrec выражения, должна быть возможность оценивать каждый <expression> каждого внутреннего определения в <body> без присвоения или ссылки на значение любого <variable> определяется. "

Однако в R6RS внутренние define s эквивалентны a letrec*. И, как и следовало ожидать, letrec* позволяет ссылаться на значение предыдущих переменных в инициализаторе для последующих переменных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...