2011-04-24 3 views
1

예 :`let '에 의해 생성 된 로컬 변수의 상태는 재귀 호출 Scheme 동안 변경됩니까?

요소가 목록에 있는지 확인하고 싶습니다. 알고리즘은 간단하다, 나는 위의 C++ 코드와 유사 뭔가를 할 수 없어, 제도 나 단일 if 문을 사용하지 않기 때문에 이제 C++로

bool element_of(const std::vector<int>& lst, int elem) { 
    for(int i(0), ie = lst.size(); i < ie; ++i) 
     if(elem == lst[i]) 
      return true; 
    return false; 
} 

그것을 할 수 있습니다. 그런 다음 임시 변수 인 result을 찾았습니다. result#f의 초기 값을가집니다. 다음으로 재귀 적으로 목록의 다음 항목 즉, cdr lst을 확인하는 함수를 호출합니다. 제 질문은 let으로 만든 변수가 새로운 함수를 시작할 때마다 초기 값으로 복원됩니다. 통화 또는 그 값은 마지막 통화까지 동일하게 유지됩니까? fold을 사용 한편

, 내 용액

(define (element-of x lst) 
    (fold (lambda (elem result) 
      (if (eq? elem x) (or result #t) result)) 
     #f 
     lst)) 

감사

답변

2

Let 호가 Let의 본체가되고 있다는 환경 변수의 새로운 세트를 생성했다 Let 구문은 전달 된 인수로 평가되는 람다가 평가 된 "구문 설탕"입니다. 예를 들어

(let ((a (func object)) 
     (b (func object2))) 
    (cons a b)) 

그래서 당신이 Let 구문 것을 볼 수 있습니다

((lambda (a b) (cons a b)) (func object) (func object2)) 

를 작성하는 것과 동일, 인수가 먼저 평가 된 후 몸이 평가되고, a의 정의와 b은 로컬 환경 범위에서 사용됩니다. 따라서 재귀 적으로 Let을 호출하면 Let 호출 본문을 입력 할 때마다 새 환경에서 본문이 평가되고 (본문이 새로 정의 된 람다 안에 있기 때문에) 로컬에 정의 된 인수의 정의 Let 범위가 달라집니다 (C++ 루프에서 찾을 수있는 것처럼 단순히 변경되거나 "다시 정의 된"변수가 아닌 새로운 람다에 의한 중첩 환경 설정에서 실제로 새로운 변수입니다).

이 말의 또 다른 방법은 변수가 C++ 재귀 함수의 로컬 범위 변수와 같은 것입니다 ... 각 함수의 스택 프레임에 대해 로컬 범위의 변수는 자체 정의를 가지며 메모리 위치 ... 로컬 범위에서 동일한 메모리 변수를 다시 사용하는 루프에서 볼 수있는 것처럼 변이 된 변수가 아닙니다. 이 도움이

희망,

제이슨

+0

감사합니다. 그래서 Scheme의 지역 변수의 메커니즘은 명령형 언어와 정확히 같습니다. – Chan

+0

일종의 ... Scheme의 환경 모델은 Scheme이 "순수한"함수 언어가 아니기 때문에 필요합니다. 변수에 대한 가변성을 허용합니다. 기본적으로 모든 변수는 기본적으로 기호 테이블 인 "환경"에있는 기호입니다. '(a a b)'키워드는 기호'a'를 지역 환경 (기호 표)에 추가하고 평가 된 값'b'에 바인드합니다. 'a'에'define '을 다시 호출하면 새로운 환경에서 그것을 호출하지 않는 한'a'를 다른 것으로 다시 바인딩합니다.이 경우 심볼 테이블에 새로운'a'를 추가하여 이전 값. – Jason

+0

Scheme의 환경 모델에 대한 자세한 내용은 다음 링크를 참조하십시오. http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-001-structure-and-interpretation-of-computer- programs-spring-2005/lecture-notes/lecture15webhan.pdf – Jason

1

let 항상 변수를 reinitialises; 새로운 바인딩 값을 제공해야하기 때문에 분명합니다. 예를 들어, ... 내부

(let ((a 42)) 
    ...) 

a는 항상 42로 밖으로 시작한다. 이전 호출에서 값을 "보유"하지 않습니다.그런데


, 난 당신이 (or result (equal? elem x))보다는 (if (eq? elem x) (or result #t) result)를 작성하는 의미 생각합니다. :-)

(or result (equal? elem x))

다음 C로 변환 ++ 코드 :
return result || elem == x; 

합니다 ( == 연산자 equal? 물론, 무엇을 수행하는 오버로드 된 것으로 가정). 이것의 이점은 result 경우이다 이미 사실이라면 더 이상의 비교는 수행되지 않습니다.

+0

네 말이 맞았다. 내 C + + 아이디어를 전송하려고 할 때, 나는 그걸로 붙어있었습니다. 고맙습니다. – Chan

관련 문제