2012-07-13 6 views
3

나는 차이가합니다 (인위적인 예를 들어 죄송합니다) 사이에 이해하지 않습니다로컬 바인딩을 만들기위한 'let'또는 'letrec'과 'define'의 차이점은 무엇입니까?

(define average 
    (lambda (elems) 

    (define length 
    (lambda (xs) 
     (if (null? xs) 
      0 
      (+ 1 (length (cdr xs)))))) 

    (define sum 
    (lambda (xs) 
     (if (null? xs) 
      0 
      (+ (car xs) (sum (cdr xs)))))) 

    (define total (sum elems)) 

    (define count (length elems)) 

    (/ total count))) 

(define average 
    (lambda (elems) 
    (letrec ((length 
       (lambda (xs) 
       (if (null? xs) 
        0 
        (+ 1 (length (cdr xs)))))) 

      (sum 
       (lambda (xs) 
       (if (null? xs) 
        0 
        (+ (car xs) (sum (cdr xs)))))) 

      (total (sum elems)) 

      (count (length elems))) 

    (/ total count)))) 

를 지금까지 내가 말할 수있는, 그들 모두는 새로운 범위를 만들고, 그 범위 내에서 서로를 참조하고 몸을 평가하고 반환하는 4 개의 지역 변수를 만듭니다.

여기에 뭔가가 누락 되었습니까? letrec은 (는) define입니까?

구현에 따라 다를 수 있습니다. 나는 Lisps의 기초를 이해하려고 노력하고있다.

답변

6

코드의 defineletrec 버전 사이에 유사점이있는 것이 맞습니다. 그러나 악마는 세부 사항에 있습니다. R5RS에서 internal define has letrec semantics. R6RS에서 internal define has letrec* semantics.

다른 점은 무엇입니까? 귀하의 코드는 실제로이 차이점을 강조 표시했습니다. lengthsum가 결합하기 때문에, 당신은 (length elems)(sum elems)의 값을 평가하고 시간을 준수 할 보장 할 수 없습니다 : Zhehao의 대답은 언급으로, 동일 lengthletrecsum 내부 totalcount의 당신의 정의가 잘못되었습니다 이러한 변수가 왼쪽에서 오른쪽으로 보장되지는 않습니다.

letrec*letrec과 비슷하지만 왼쪽에서 오른쪽으로의 보증이 있습니다. 따라서 letrecletrec*으로 변경하면 괜찮습니다.

지금, 다시 내 최초의 코멘트에 : defineletrec 의미를 사용 R5RS의 내부 있기 때문에, 코드 심지어 define 버전은 R5RS 구현에서 잘못된 것입니다,하지만 letrec* 의미가있는 R6RS 구현, 아래에 괜찮을 것입니다.

+0

엄밀히 말하면, '길이'와 '합'은 * 묶여 * (위치에) 보장됩니다; 보장되지 않는 것은 그들이 초기화 값을 할당 받았다는 것이다. R5RS - R7RS는 'total'과 'count'에 대한 초기화 절에서 이러한 값을 참조하는 것이 "오류"라고합니다. (그러나이 구현에 대해서는이 오류를 감지하고 불평 할 필요가 없다고 생각합니다.) 차이점에 대한 자세한 내용은'letrec' /'letrec *'을 참조하십시오. http://stackoverflow.com/q/13078165/272427 – dubiousjim

4

let/letrec 및 define은 모두 로컬 범위 정의를 생성합니다. 그러나 let/letrec은 내부와 암시 적 begin 문이 아니라면 더 편리합니다. 예를 들어, 다음 코드는 let 매크로를 사용합니다.

(define (test) (let ((x 1)) x)) 

로컬 범위 정의를 사용하여 동일한 코드

(define test (lambda() (define x 1) x)) 

이것은 인위적인 예를의 종류이지만, 일반적으로 지역의 바인딩을 수행하는 매크로를하게 사용하는 것이 더 많은 기능 간주 될 것이다.

또한 예제 코드는 letrec을 올바르게 사용하지 않습니다. letrec 선언 안에 정의가 필요하지 않습니다 (실제로는 거기에 있으면 안됩니다).

+0

위대한 답변! 내 답변에서 언급했듯이 R5RS에서 OP 코드의'define' 버전조차'letrec' 버전뿐만 아니라 정확하지 않습니다. –

+0

'letrec' 안에서'define '에 관한 좋은 지적은 ... 내가 그것을 썼을 때 피곤했을 것입니다.+1 –