2014-01-11 4 views
2

В настоящее время я пишу metacircular оценщик в Схеме, следуя шагам книги SICP.Scheme letrec бесконечная окружающая среда

В упражнении я просил осуществить letrec, что я делаю следующим образом:

(define (letrec->let exp) 
    (define (make-unassigned var) 
    (list var '*unassigned*)) 
    (define (make-assign binding) 
    (list 'set! (letrec-binding-var binding) 
      (letrec-binding-val binding))) 
    (let ((orig-bindings (letrec-bindings exp))) 
    (make-let 
    (map make-unassigned 
      (map letrec-binding-var orig-bindings)) 
    (sequence->exp 
     (append 
     (map make-assign orig-bindings) 
     (letrec-body exp)))))) 

Однако, когда я оцениваю выражение следующим образом, он переходит в бесконечный цикл:

(letrec 
    ((a (lambda() 1))) 
    (+ 1 (a))) 

Пропустить что-нибудь?

(Full Source Code at GitHub).

+0

Ваш код когда-либо работал для простейших случаев, таких как '(let ((x 1)) x)'? –

+0

Этот вопрос вводит в заблуждение. проблема в этом коде находится на гораздо более глубоком (ранее) уровне и не имеет ничего общего с letrec. –

ответ

1

Я проверил результат результат преобразования из (let ((x 1)) x) и получил:

((lambda (x) (x)) 1)

вместо:

((lambda (x) x) 1)

, очевидно, проблема заключается в let обработки тела. Если бы я тебя, я хотел бы использовать функцию полезности:

(define (implicit-begin exps) 
    (if (= 1 (length x)) 
     (car x) 
     (cons 'begin x))) 

Кстати: я бы сказал, что ваша letrec реализация не очень правильно. Ваше преобразование возвращает:

(let ((x1 *unassigned*>) ... (xn *unassigned*)) 
    (set! x1 ...) 
    ... 
    (set! xn ...) 
    body) 

Она гораздо больше напоминает letrec*, который вычисляет выражения для привязок переменных в левом-ро-правильный порядок (сама схема не определяет порядок вычисления аргументов):

Синтаксиса: letrec * привязок тело

Similar to ‘letrec’, except the INIT expressions are bound to their 
variables in order. 

‘letrec*’ thus relaxes the letrec restriction, in that later INIT 
expressions may refer to the values of previously bound variables. 

более правильный код будет:

(let ((x1 *unassigned*) ... (xn *unassigned*)) 
    (let ((t1 ...) ... (tn ...)) 
    (set! x1 t1) 
    ... 
    (set! xn tn)) 
    body) 
+0

Вы хотите поставить implicit-begin в моей функции расширения-let, чтобы он мог иметь (автомобиль exps) в лямбда-теле напрямую? –

+0

проблема заключается в том, что 'make-lambda' что-то принимает, но' let-body' нарушает это предположение в определенных ситуациях. –

Смежные вопросы