2010-07-02 7 views
3

이 계승을 계산하는 함수의 다음 실행을 고려내부 재귀 프로 시저의 이름을 지정하는 작업을 왜하지 않겠습니까?

(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시 에러가 없지만 :

(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을 사용하여 재작 시도 [1] 정의 실행 결과 :

#;> (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의 반복 버전에 따라 SICP 1.2.1 http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-11.html#%_sec_1.2.1

+0

사람들이 거기 밖으로 계획을 해킹하고 있다는 것을 알고있는 것이 좋다 ... :) – galambalazs

답변

8

가 어떻게이하자 버전 작업을 할 수있는 제도 프로그래밍 언어, 4 판을?

let 대신 letrec을 사용하십시오.

+0

본질적인 차이점은 let''re 절차의 본문은 let'd 절차의 본문은 참조 할 수 있지만 그 자체는 참조 할 수 없다는 것입니다. – erjiang

6

R. 켄트 Dvbvig 말한다 :


실제로, let 표현식은 람다 및 프로 시저 응용 프로그램의 측면에서 정의 된 구문 확장입니다. 은 모두 핵심 구문 양식입니다. 일반적으로 다음 형식의 표현은

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

과 동일합니다.

(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 

그리고는 lambda의 몸에 paramenter 위의 강조로 문제가 그 fac-tail-helper-2 이름이 표시되는지 분명해진다 : fac-tail-2가 동등하다는 것을 의미

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

매개 변수 fac-tail-helper-2에 할당 된 lambda 내의 이름이 아닙니다.

[1]의 2.5 절, "람다 표현식"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)))) 

그리고 간단한 단일 재귀에 대한 letrec의 INSEAD을 사용할 수있는 명명 된 let입니다.

(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-tail-helper에 묶여있는 암시 적 람다 정의를 숨기고 있지만.