2010-07-02 1 views
3

Рассмотрим следующую реализацию функции для вычисления факториала: [1]Почему не будет `позволять` работать для именования внутренних рекурсивных процедур?

(define fac-tail 
    (lambda (n) 
    (define fac-tail-helper 
     (lambda (n ac) 
     (if (= 0 n) 
      ac 
      (fac-tail-helper (- n 1) (* n ac))))) 
    (fac-tail-helper n 1))) 

Я попытался переписать с помощью let для внутреннего определения:

(define fac-tail-2 
    (lambda (n) 
    (let ((fac-tail-helper-2 
      (lambda (n ac) 
       (if (= 0 n) 
        ac 
        (fac-tail-helper-2 (- n 1) (* n ac)))))) 
    (fac-tail-helper-2 n 1)))) 

Там нет ошибки в define время, но результаты выполнения в:

#;> (fac-tail-2 4) 
Error: undefined variable 'fac-tail-helper-2'. 
{warning: printing of stack trace not supported} 

Как я могу сделать let версию работы?

Схема версия SISC v 1.16.6

[1] на основе итерационного версии factorial в разделе 1.2.1 SICP http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-11.html#%_sec_1.2.1

+0

Полезно знать, что есть люди, взломавшие схему там ... :) – galambalazs

ответ

8

Как я могу сделать Выпускаемую версию работы?

Использовать letrec вместо let.

+0

Существенное отличие состоит в том, что тело процедуры letrec'd может ссылаться на себя, пока тело процедуры let'd не может. – erjiang

6

Р. Кент Dvbvig говорит:


Фактически, выражение let является синтаксическим расширением, действующим в терминах лямбда-процедуры и процедуры, являются как синтаксическими формами. В общем, любое выражение вида

(let ((var expr) ...) body1 body2 ...) 

эквивалентно следующему.

((lambda (var ...) body1 body2 ...) 
expr ...)" [1] 

Это означает, что fac-tail-2 эквивалентно:

(define fac-tail-2 
    (lambda (n) 
    ((lambda (fac-tail-helper-2) 
     (fac-tail-helper-2 n 1)) ;; <== scope where fac-tail-helper-2 is visible. 
    (lambda (n ac) ;; this lambda is assigned to fac-tail-helper-2 
     (if (= 0 n) 
      ac 
      (fac-tail-helper-2 (- n 1) (* n ac))))))) ;; <=== problem 

И становится ясно, что проблема заключается в том, что fac-tail-helper-2 имя видимым как paramenter в теле lambda указывалось выше , но это не имя в пределах lambda, которое назначено параметру fac-tail-helper-2.

[1] Раздел 2.5, "лямбда-выражение" из Схемы Языка программирования, 4-е изданияhttp://scheme.com/tspl4/start.html#SECTGSLAMBDA

0

Две другие альтернативы, добавляемые для полноты.

Схема Язык программирования, 4-е издание Раздел 3.2 имеет две другие альтернативы для использования let и рекурсивных функций. http://scheme.com/tspl4/further.html#./further:h2

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

(define fac-tail-4 
    (lambda (n) 
    (let ((fac-tail-helper 
      (lambda (fac-tail-helper n ac) 
       (if (= 0 n) 
        ac 
        (fac-tail-helper fac-tail-helper (- n 1) (* n ac)))))) 
     (fac-tail-helper fac-tail-helper n 1)))) 

И чем проще, названный let, который может быть использован в INSEAD в letrec для одного рекурсии.

(define fac-tail-3 
    (lambda (x) 
    (let fac-tail-helper ((n x) (ac 1)) 
     (if (= 0 n) 
      ac 
      (fac-tail-helper (- n 1) (* n ac)))))) 

Хотя эта версия скрывает неявное определение лямбды, который был привязан к FAC-хвост-помощнику.

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

  • Нет связанных вопросов^_^