문제

나는 실제로 재미를 위해 책을 읽고 있지만 숙제로 간주 될 수 있습니다. 어쨌든, 나는이 언어로 지역 상태 변수에 전혀 익숙하지 않습니다 ... 예를 들어이 코드를 예로 들어보십시오.

(define flip
  (let ((count 0))
    (lambda ()
      (if (= 0 count)
          (begin (set! count 1) count)
          (begin (set! count 0) count)))))

이 코드가 왜 1과 0 사이에서 번갈아가나요? 이 함수가 호출 될 때마다 카운트가 0의 값이 주어집니다! 파이썬에 해당하는 것은 다음과 같습니다.

class Flip:
    def __init__(self):
        pass
    def __call__(self):
        count = 0
        if count == 0:
            count = 1
            return count
        else:
            count = 0
            return count

이것은 매번 같은 것을 반환합니다. 난 혼란스러워 ...

도움이 되었습니까?

해결책

기능적 언어에 대한 컴파일러를 작성하는 경험이 거의 없으므로 해당 기능이 메모리에 저장/표현되는 방법에 대한 간단한 설명이 순서대로 진행됩니다. 모든 함수는 대략 쌍 (e, f)으로 생각할 수 있으며, 여기서 e는 자유 변수 세트이며 F는 함수 자체의 "코드"입니다. 함수를 호출하면 e의 값을 가져 와서 F의 변수에 대한 값을 대체 한 다음 해당 값을 사용하여 코드를 실행합니다.

따라서 예제와 관련된 경우 변수 "Flip"을 LET 표현식에 의해 반환 된 함수로 정의했습니다. 그 기능은 람다 내부의 물건입니다. "카운트"는 람다 외부에서 정의되므로 자유 변수이므로 기능 환경에 저장됩니다. 그런 다음 전화 (플립)를 호출 할 때마다 통역사는 Lambda의 코드로 이동하여 환경에서 "카운트"의 가치를 찾아야하며, 그렇게하고, 변경하고, 반환해야한다는 것을 알 수 있습니다. 그렇기 때문에 당신이 그것을 부를 때마다 "count"에 저장된 가치가 지속되는 이유입니다.

플립을 호출 할 때마다 계산을 원한다면 LET 표현을 Lambda 내부에 넣으므로 자유 변수 대신 바운드 변수입니다.

다른 팁

람다는 폐쇄입니다. 로컬로 정의되지 않거나 매개 변수 중 하나가 가장 가까운 어휘 환경에 바인딩되는 자유 변수 (카운트)를 참조하는 함수입니다.

불리는 기능은 "플립"이 아닌 람다입니다. 플립은 (let ...) 표현에서 돌아온 람다에게 준 이름 일뿐입니다.

파이썬은 언어를 알지 못하지만 Count는 가변적인 로컬이 아닌 플립 객체의 구성원이어야합니다. 전화.

플립 기능이 실제로 작동하기 때문입니다 함수를 반환합니다 (Lambda 내부에 정의 됨)

반환 된 기능을 호출 할 때마다 환경을 수정합니다.

당신이 그것에 대해 생각한다면 허락하다 Lambda 함수가 귀하에게 반환 될 때 환경을 한 번만 생성하고 (및 카운트를 0으로 초기화합니다).

어떤 의미에서 Lambda는 마지막 프레임이 초기화 된 환경을 사용하는 기능 객체를 만듭니다. 허락하다 단일 변수 카운트. 기능을 호출 할 때마다 환경을 수정합니다. 전화하면 튀기다 두 번째로는 다른 환경이있는 다른 기능 객체를 반환합니다. (0으로 초기화 된 카운트) 그런 다음 두 기능을 독립적으로 전환 할 수 있습니다.

어떻게 작동하는지에 대한 결정을 완전히 원한다면 읽어야합니다. 환경 모델.

더 비슷합니다

class Flip:
    def __init__(self):
        self.count = 0
    def __call__(self):
        if self.count == 0:
            self.count = 1
            return self.count
        else:
            self.count = 0
            return self.count

자세한 설명으로 업데이트 :체계의 함수는 자유 변수 주변에서 "닫는"폐쇄입니다. count, 그것은 외부의 범위에 정의되어 있습니다. 그 방식 count a let 신체 역할만으로도 기능이 액세스 할 수있는 유일한 기능이라는 것을 의미합니다. count 효과적으로 함수에 첨부 된 일종의 개인 돌연변이 상태.

이것은 "객체"가 전통적으로 SICP의 체계에서 만들어지는 방식입니다. let 변수 (인스턴스 변수, 초기 값으로 초기화 된 인스턴스 변수)를 정의하고 신체에서 인스턴스 변수에 대한 액세스를 공유 한 "메소드"인 함수를 정의합니다. 그렇기 때문에 파이썬 클래스를 사용하여 진행중인 일을 나타내는 것이 당연한 이유입니다. count 인스턴스 변수입니다.

Python 3.x로의 더 문자 그대로 번역은 다음과 같습니다 (Python은 let (한정 스코프 로컬 변수 선언) 구문 및 Python 's lambdas는 진술을받지 않기 때문에 사용할 수 없습니다) :

count = 0

def flip():
    nonlocal count
    if count == 0:
        count = 1
        return count
    else:
        count = 0
        return count

# pretend count isn't in scope after this

원래 코드의 문제점은 필수 스타일에 큰 영향을 미친다는 것입니다. 보다 관용적 인 해결책은 다음과 같습니다.

(define (flip)
  (let ((flag #t))
    (lambda ()
      (set! flag (not flag))
      (if flag 1 0))))

귀하의 질문에 답하기 위해 Ooboo, 귀하는 기능을 반환하는 함수를 원합니다.

(define make-flipper
  (lambda ()
    (let ((count 0))
      (lambda ()
    (let ((v count))
      (set! count (- 1 count))
      v)))))

;; test it
(let ((flip-1 (make-flipper)))
  (format #t "~s~%" (flip-1))  
  (format #t "~s~%" (flip-1))
  (format #t "~s~%" (flip-1))

  (let ((flip-2 (make-flipper)))
    (format #t "~s~%" (flip-2))
    (format #t "~s~%" (flip-2))
    (format #t "~s~%" (flip-2))))

세트를 사소하게 변경할 수 있습니다! 플립 퍼가 아닌 카운터가되도록 라인.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top