2014-05-25 4 views
-1

let, letrec, let *의 차이를 고민하고 있습니다 ... 스키마가 제 1 차 프로그래밍 언어가 아니기 때문에 제 메모리는 오랜 시간 동안 존재하지 않습니다 .. 이 함수가 있습니다. 지금 나는 letrec과 매우 혼란 스럽다. 이것은 다시 재귀이다. 나는 이해할 수있다. 그러나이 코드에서 연결을 충분히 할 수는 없다. (어쩌면 여전히 재귀에 대해 혼란스러워 할 것이다.) 왜 여기에 letrec가 필요한지 설명 할 수있다letrec, Scheme의 혼동

(define myFunc 
    (lambda (start end res func) 
    (letrec ((func:rec_func 
       (lambda (x i y) 
       (if (>= i start) 
        (func:rec_func (cons i x) (- i res) (cons (func i) y)) ;; line6 
        (cons x (cons y '()))))))        ;; line7 
     (func:rec_func '() end '())))) 

(편집) 는 내가 이해가 꼬리 재귀의

-> [Q1] 꼬리 재귀가 있습니까?

-> [Q2] 그런 다음 꼬리 재귀를 위해 항상 letrec을 사용해야합니까? 예 다음 행한다면

이 함수 개시 경계 Y X의 목록을 반환 단부 그래서 그것은 인덱스를 검사 나 내부 경계 6

된다 -> [Q3 그리고, 무엇 LINE6을 수행 ? 내 기억이 맞다 func:rec_func의 몸 자체를 의미하기 때문에,이 구조는 letrec보다는 let 또는 let*이 필요한 경우 내가 LINE6에게

답변

0

[Q1] 꼬리 재귀가 발생합니까?

응답 예, 꼬리 재귀를 수행합니다.

[Q2] 그렇다면 꼬리 재귀를 위해 항상 letrec을 사용해야합니까?

응답 질문을 해석하는 데는 두 가지 방법이 있습니다.

  1. 꼬리 재귀에는 항상 letrec을 사용해야합니까? 네가 이걸 물어볼 생각은 아닌 것 같아. 하지만 ...

    대답은 없습니다. 꼬리 재귀를 위해 최상위 람다 함수를 사용할 수도 있습니다.

  2. letrec은 항상 꼬리 재귀를 사용해야합니까?

    이에 대한 대답은 다음과 같습니다. 모든 재귀 함수가 꼬리 재귀가되는 것이 좋습니다. 할 수 있다면, 꼬리 재귀 적으로 만들어야합니다.

[Q3] 다음 LINE6을 무엇을?

6 번 줄 코드는 재귀 호출을 수행합니다.

end5입니다, 이제 start0라고하자, 그리고 res1입니다. func:rec_func에 대한 첫 번째 호출에서 , i5이고 y은 비어있는 목록 ()입니다. x은 빈 목록입니다. (5), 4((func 5) : 제 재귀 함수는 라인 (6)으로 불린다

는 인수로 평가 (cons i x), (- i res)(cons (func i) y)이다.

다음 반복에서 인수는 (4 5), 3((func 4) (func 5))입니다.

istart 미만이 될 때까지 계속됩니다. 그러면 재귀가 결과와 함께 멈 춥니 다. ((0 1 2 3 4 5) ((func 0) (func 1) (func 2) (func 3) (func 4) (func 5)))

행 7의 코드는 재귀의 종료 조건이 충족 될 때 실행됩니다 ((>= i start)이 false 일 때).

1

을 얻을 수 없습니다. 여기서 let 또는 let*을 사용한 경우 중첩 된 람다 안에있는 func:rec_func 기호는 외부의 최상위 양식에 바인딩되거나 정의가 없으면 undefined로 바인딩됩니다. 둘 다 원하는 것은 아닙니다.

3

letrec, let 및 let *과의 차이점은 프로그램에서 사용할 수있는 선언을 할 때입니다. 요약하자면

(letrec ((X (you could use X here)) 
     (Y (you could use X here too)) 
     ) 
    (X also is available here) 
) 


(let ((X (nope, X isn't declared yet)) 
     (Y (in fact, no declaration body will see X)) 
     ) 
    (But X is available here) 
) 


(let* ((X (X isn't available here)) 
     (Y (but you could use it here)) 
     ) 
    (X also is available here) 
) 

:

  1. letrec로 선언 된 변수의 범위는 모든 letrec의 몸 안에 있습니다. 컴파일러는 마술을하기 때문에 선언이 끝난 후에 참조가 대체됩니다.
  2. let *으로 선언 된 변수의 범위는 변수 선언 후 let * 범위의 모든 표현식입니다.
  3. 그리고 let으로 선언 된 변수의 범위는 선언 부분이 아니라 let의 본문입니다.