2011-03-23 2 views
34

좋습니다. 이것은 기본적인 질문입니다. SICP 비디오를 따르고 있는데, define, letset!의 차이점에 대해 다소 혼란 스럽습니다.정의, 설정 및 설정의 차이점!

1) 비디오의 Sussman에 따르면 define은 한 번만 값을 지정할 수 있습니다 (REPL에있는 경우 제외). 특히 줄에 2 개의 정의가 허용되지 않습니다. 그러나 Guile은이 코드를 행복하게 실행합니다.

(define a 1) 
(define a 2) 
(write a) 

예상대로 2를 출력합니다. 나는이 수행하려고 할 경우 때문에 상황이 조금 더 복잡하다 (편집 : 위의 정의 후)

(define a (1+ a)) 

나는 오류가 발생,

(set! a (1+ a)) 

이 허용된다. 여전히 나는 이것이 set!define 사이의 유일한 차이라고 생각하지 않습니다. 그게 무엇입니까?

2) definelet의 차이는 나를 더욱 괴롭힌다. 나는 이론적으로 let이 로컬 범위의 변수를 바인딩하는 데 사용된다는 것을 알고 있습니다. 그럼에도 불구하고,이 내가

(define (f x) 
    (let ((a 1)) 
     (+ a x))) 

(define (g x) 
    (define a 1) 
    (+ a x)) 

fg 일 같은으로 대체 할 수 있습니다 예를 들어, define와 동일하게 작동 나에게 보인다 특히 변수 a 외부 언 바운드입니다 g도 있습니다.

이 유용한 점을 알 수있는 유일한 방법은 let이 전체 함수 정의보다 짧은 범위를 가질 수 있다는 것입니다. 여전히 그것은 필요한 범위를 생성하기 위해 익명의 함수를 추가 할 수 있으며 자바 스크립트 에서처럼 익명의 함수를 추가하여 바로 호출 할 수 있습니다. 그렇다면 let의 실제 이점은 무엇입니까?

+0

당신이해야 제대로 들여 쓰기'(+ A X)'f''의 정의, 그것은 let''의 범위 내에서의로. –

+0

당신이 맞아요, 고마워요 – Andrea

+0

그것은 당신이 사용하는 체계 체계에 달려 있습니다. – knivil

답변

14

(1+ a) 대신 (+ 1 a)을 의미합니까? 후자는 구문 적으로 유효하지 않습니다.

(define (f x) 
    (let ((a 1))) 
    (+ a x)) 

는 아니지만 let 의해 정의 된 변수

범위는

(define (f x) 
    (let ((a 1)) 
    (+ a x))) 

구문이 가능하므로, 후자에 결합된다.

(define (g x) 
    (define a 1) 
    (display (+ a x)) 
    (define b 2) 
    (+ a x)) 

첫 번째 이유는이 코드는 오류를 생성하면서

(define (g x) 
    (define a 1) 
    (+ a x)) 

:

모든 변수에 따라서 다음의 코드는 가능한 함수의 시작 부분에 define D해야 정의 이후의 표현은 다른 정의가 없음을 의미합니다.

변수를 정의하지 않고 변수에 새 값을 할당하는 데 사용됩니다. 따라서 이러한 정의는 의미가 다음과 같이 set!에 대한

(define (f x) 
    (set! ((a 1)) 
    (+ a x))) 

(define (g x) 
    (set! a 1) 
    (+ a x)) 

유효한 사용은 다음과 같습니다

이 낙담 비록
(define x 12) 
> (set! x (add1 x)) 
> x 
13 

, 계획은 기능적인 언어이기 때문에.

+8

'1 +'는 일부 버전의 Scheme에서 함수이므로 호출이 유효합니다. –

+0

사실,'define'은 함수의 시작 부분에서만 허용된다는 사실은 흥미 롭습니다. 이것은 최소한 특정 상황에서 익명 함수를 unsigned하여 함수 범위를 만들 가능성을 배제합니다. – Andrea

+0

@Jeremiah : Racket의 add1과 동일한가요? 인수를 증가시키는 함수입니까? –

2

당신은 두 번 이상 define 이상을 사용 할 수 있습니다하지만 관용적하지 의 : define 당신이 환경 정의를 추가하는 것을 의미하고 set! 당신이 몇 가지 변수를 돌연변이 있습니다 의미한다.

나는 계략에 대해 잘 모르겠어요 그리고 왜 a 아직 정의되지 않은 경우 (set! a (+1 a))하지만 이 문제가 해결되지해야 허용합니다. 대개 define을 사용하여 새 변수를 입력하고 나중에 set! 으로 변경해야합니다.

당신은 일반적으로 정확히 let가 확장 무엇 사실, 대신 let의 익명 함수의 응용 프로그램을 사용할 수 있습니다, 그것은 거의 항상 매크로입니다. 이들은 동일합니다 : 당신이 let을 사용하십시오

(let ((a 1) (b 2)) 
    (+ a b)) 

((lambda (a b) 
    (+ a b)) 
1 2) 

이유가 명확하다는 것입니다 : 변수 이름은 바로 옆 값입니다.

내부 정의의 경우 Yasir이 임을 확신하지 않습니다. 적어도 내 컴퓨터에서는 R5RS 모드에서 Racket을 실행하고 정규 모드에서는 함수 정의의 중간에 나타나는 내부 정의가 허용되지만 표준이 무엇을 말하는지는 확실하지 않습니다. 어떤 경우에서, 나중에 SICP에서, 내부 정의 자세의 까다 로움은 입니다. 4 장에서는 내부적으로 상호 회귀하는 방법 인 을 구현하는 방법을 탐구하고 반이중 인터프리터 구현의 의미에 대해 설명합니다.

이렇게 붙어있어! SICP는 훌륭한 책이며 비디오 강연은 훌륭합니다.

28

혼란은 합리적입니다. 'let'과 'define'모두 새 바인딩을 만듭니다. '하자'라는 한 가지 이점은 그 의미가 매우 잘 정의되어 있다는 것입니다. 평범한 '하자'가 무엇을 의미하는지에 대한 다양한 제도 체계 (라켓 포함) 사이에는 전혀 의견이 분분하지 않습니다.

'정의'양식은 다른 물고기 주전자입니다. '렛트'와 달리 괄호로 묶여있는 본문 (바인딩이 유효한 영역)을 둘러싸 지 않습니다. 또한 최상위 레벨과 내부적으로 다른 것을 의미 할 수도 있습니다. 다른 체계 체계는 '정의'에 대해 극적으로 다른 의미를 갖는다. 사실, 라켓 (Racket)은 최근 '정의'의 의미를 새 컨텍스트를 추가하여 변경했습니다.

반면에 '정의'하는 사람; 들여 쓰기가 적으며 대개 재귀 적 및 상호 재귀 적 프로 시저의 자연적인 정의를 허용하는 "do-what-I-mean"수준의 범위 지정이 있습니다. 사실, 나는 이것으로 다른 날에 물렸다. :).

마지막으로 '설정!'; '하자', '설정!' 은 꽤 간단합니다. 기존 바인딩을 변경합니다.

FWIW, DrRacket에서이 범위를 이해하는 한 가지 방법은 "구문 확인"단추를 사용하고 다양한 식별자 위로 마우스를 가져 가면 바인딩 된 위치를 확인하는 것입니다.

+0

감사합니다. 나는'set!'** sfter ** 디펜스를 사용하고 있음을 분명히하기 위해 질문을 편집했다. 그 단락의 요점은 이전 값에 따라 변수를''설정할 수있다 '는 것이었지만 이전 값에 따라 변수를''정의 할 수는 없습니다. – Andrea

+0

오른쪽; 왜냐하면 '정의'의 범위에는 바인딩 자체의 오른쪽이 포함되기 때문입니다. 이것은 '정의'가 재귀 프로 시저를 만들 수 있기 때문에 중요합니다. '결합'(Y 결합자와 같은 트릭을 사용하지 않는 한)에서는 불가능합니다. –

+0

치킨 계획에서! 새로운 바인딩을 도입하는 데에도 사용할 수 있습니다. 이것은 한 번 탐험적인 프로그래밍을하는 동안 나를 위태롭게했다. 예를 들어, (정의 (foo a) (set! ba)) 환경의 신선한 실행에 행복하게 작동합니다 : csi -e '(define (foo a) (set! b (* a 2))) (foo 42) (디스플레이 b) '. 그것은 설정된 것 같습니다! 명명 된 변수를 찾을 때까지 대부분의 로컬에서 글로벌 환경으로 이동합니다. 4.9.0.1을 사용하고 있습니다. –

5

존 클레멘트 대답은 좋습니다. 경우에 따라 define이 Scheme의 각 버전에서 무엇이되는지 확인할 수 있으며 이는 어떤 일이 벌어지고 있는지 이해하는 데 도움이 될 수 있습니다. 예를 들어

, 체즈 계획의 8.0 (특히, 자신의 define 단점이있는 R6RS을 WRT.!) :

> (expand '(define (g x) 
      (define a 1) 
      (+ a x))) 
(begin 
    (set! g (lambda (x) (letrec* ([a 1]) (#2%+ a x)))) 
    (#2%void)) 

을 당신은 "최상위"정의가 set!하게 볼 (비록 경우에 따라 define을 확장하면 변경 될 수 있습니다.)하지만 내부 정의 (즉, 다른 블록 내부의 define)는 letrec*이됩니다. 다른 체계는 그 표현을 다른 것으로 확장 할 것입니다.

MzScheme의 v4.2.4 :

> (expand '(define (g x) 
      (define a 1) 
      (+ a x))) 
(define-values 
(g) 
(lambda (x) 
    (letrec-values (((a) '1)) (#%app + a x)))) 
관련 문제