Frage

Ich lese eigentlich das Buch zum Vergnügen, aber es könnte Hausaufgaben in Betracht gezogen werden. Auf jeden Fall fühle ich mich nicht wohl mit lokalen Zustandsvariablen überhaupt mit dieser Sprache ... Nehmen Sie zum Beispiel diesen Code:

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

Warum wird dieser Code wechselt zwischen 1 und 0? Zahl ist der Wert von 0 jedes Mal diese Funktion gegeben genannt wird! Ein Python-äquivalent wäre:

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

Das gibt die gleiche Sache jedes Mal. Ich bin verwirrt ...

War es hilfreich?

Lösung

Ich habe eine wenig Erfahrung mit dem Schreiben von Compilern für funktionale Sprachen, so vielleicht eine kurze Beschreibung, wie diese Funktion gespeichert ist / im Speicher dargestellt in Ordnung ist. Jede Funktion kann grob als ein Paar (E, F) gedacht werden, wo E die Menge der freien Variablen ist, und F ist der „Code“ der Funktion selbst. Wenn Sie die Funktion aufrufen, ist es die Werte in E nimmt und ersetzt die in der Variablen in F, und führt dann den Code unter Verwendung dieser Werte.

Also, wo Ihr Beispiel betrifft, so haben Sie die Variable „Flip“ definiert die Funktion von Ihrem lassen Ausdruck zurückgegeben werden. Diese Funktion ist der Stoff in Ihrem Lambda. Da „count“ außerhalb des Lambdas definiert ist, ist es eine freie Variable, so ist es in der Funktion der Umgebung gespeichert. Dann jedes Mal, wenn Sie (Flip) nennen, geht der Interpreter auf den Code in dem Lambda, sieht, dass es den Wert von „count“ in der Umgebung sehen muss, das tut, ändert sich und kehrt zurück. Deshalb jedes Mal, wenn Sie es nennen, wird der Wert in „count“ gespeichert bleibt.

Wenn Sie zählen möchten, Null sein, jedesmal wenn Sie Flip nennen, setzen Sie den let Ausdruck innerhalb der Lambda, so ist es eine gebundene Variable ist anstelle einer freien Variablen.

Andere Tipps

Das Lambda ist ein Verschluss. Es ist eine Funktion, die eine freie Variable (count) verweist, die nicht lokal definiert sind oder einer der Parameter, auf die nächste einschließelexikalische Umgebung gebunden ist.

Die Funktion aufgerufen wird, ist das Lambda, nicht „kippen“. Flip ist nur ein Name, den Sie das Lambda gegeben haben, die aus dem (let ...) Ausdruck zurückgegeben wird.

Wie für den Python, ich weiß nicht, die Sprache, aber es sieht aus wie Graf Mitglied des Flip-Objekts sein sollte, nicht ein lokale Variable auf Anruf .

Weil Ihre Flip-Funktion tatsächlich gibt eine Funktion (die innerhalb Lambda definiert ist)

Jedes Mal, wenn Sie die zurückgegebene Funktion aufrufen, es ändert seine Umgebung.

Wenn man darüber nachdenkt, die lassen die Umwelt schafft (und initialisiert auf 0 count) nur einmal -., Wenn die Lambda-Funktion an Sie zurückgeschickt wird,

In einem gewissen Sinne Lambda erzeugt ein Funktionsobjekt für Sie die Umgebung verwendet, deren letzten Frame in wurde initialisiert let mit einer einzigen Variablen zählen. Jedes Mal, wenn Sie Ihre Funktion aufrufen, es ändert seine Umgebung. Wenn Sie rufen Flip ein zweites Mal ist es eine andere Funktion Objekt mit anderen Umgebung zurückgibt. (Count auf 0 initialisiert) Sie können dann die beiden functors wechseln unabhängig.

Wenn Sie möchten, voll undestand, wie es funktioniert, sollten Sie über environmantal Modell lesen.

es ist mehr wie

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

Update mit mehr Erklärung: Die Funktion in Schema ist ein Verschluss, der um die freie Variable count „schließt“, die in dem Schutzbereich außerhalb definiert ist. Die Art und Weise, dass count in einem let nur mit der Funktion wie der Körper definiert ist, bedeutet, dass die Funktion die einzige Sache ist, die darauf zugreifen können -. count effektiv eine Art privaten wandelbar Staat zu machen, die an die Funktion gebunden ist

Dies ist die Art und Weise „Objekte“ sind traditionell in Schema in SICP geschaffen - ein let hat eine Reihe von Variablen (die Instanzvariablen, auf ihre Anfangswert initialisiert), und in dem Körper definiert eine Reihe von Funktionen definieren, welche sind „Methoden“, die den Zugriff auf die Instanzvariablen geteilt haben. Deshalb ist es hier natürlich eine Python-Klasse zu verwenden, um darzustellen, was los ist, mit count ist eine Instanzvariable.

Eine wörtliche Übersetzung in Python 3.x wäre so etwas wie diese (beachten Sie, dass es nur annähernd wie Python keine let (begrenzten Umfang lokale Variablendeklaration) Syntax und lambdas Pythons kann nicht verwendet werden denn sie nehmen Aussagen nicht wichtig):

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

Das Problem mit dem Original-Code ist, dass es einen starken Einfluss des Imperativs Stil. Eine idiomatische Lösung wird sein:

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

Zur Beantwortung der Frage in Ihnen ooboo kommentieren, möchten Sie eine Funktion, die eine Funktion gibt

(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))))

Sie können trivialerweise die Menge ändern! Linie, so dass es zu einem Zähler, kein Flipper (nützlicher).

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top