2009-03-17 14 views
8

Ich bin ein Scheme-Interpreter zu schreiben, und ich bin mit einer gültigen let Anweisung wie konfrontiert:Lisp Auswertung von lassen Aussagen

;; should print 7 
(let ((a 4) (b 3)) 
    (let ((a (* a a)) 
      (b (* b b))) 
     (+ a b) 
     (- a b))) 

Mein Dolmetscher implementiert nur eine rein funktionale Teilmenge von Scheme, so wird es keine sein Nebenwirkungen wie eingestellt!. Warum würden Sie in einer rein funktionalen Sprache mehrere Ausdrücke innerhalb einer let-Anweisung wie oben zulassen?

Und schriftlich meinen Dolmetscher, gibt es irgendeinen Grund, dass ich alles außer dem letzten Ausdruck im Lassen bewerten sollte? Es scheint, dass sie das Ergebnis der letzten bewerteten Aussage nie beeinflussen könnten.

Antwort

2

Du hast Recht (fast): Wenn Sie eine rein funktionale Teilmenge von Scheme sind Implementierung (dh keine set!, set-car!, set-cdr!) dann jeder Ausdruck, aber die letzte in einem let ihren Rückgabewert entfernt haben geworfen, und Da Sie garantiert keine Nebenwirkungen haben, besteht keine Gefahr, sie still zu ignorieren.

jedoch gibt es einen kleinen Fall, dass Sie berücksichtigen müssen, und das ist, wenn die vorhergehenden Ausdrücke define s sind:

(let ((x 3)) 
    (define y 4) 
    (+ x y)) 

Dies sowohl rechtliche als auch funktionell ist. Allerdings gibt es einige gute Nachrichten - innerhalb eines Blocks (wie ein let) müssen Sie alle Ihre s oben haben. Wie in, das ist nicht legal Schema betrachtet:

(let ((x 3)) 
    (+ 2 3) 
    (define y 4) 
    (+ x y)) 

Das bedeutet, dass, wenn ein Block Auswertung, alles, was Sie tun müssen, um für define s die oben scannen und wickeln Sie sie in den entsprechenden letrec Ausdruck, dann gehen Sie zu Ignoriere alle außer dem letzten Ausdruck (den du dann zurückgeben würdest).

bearbeiten:antti.huima macht einen ausgezeichneten Punkt über Anruf/cc.Wenn Sie Fortsetzungen in Ihre Implementierung einbeziehen, können Sie nicht viele Annahmen darüber treffen, wann die Dinge bewertet werden.

1

Okay, die let erstellt nur eine Bindung, wie eine define. Es gibt nichts, was eine gebundene Variable wie set! ändern würde. So, jetzt, darüber nachdenken, was die Scope Ihrer Namen ist: Ist die a der '(+ a b) the same as the a' Sie an 4 gebunden? (Hinweis: no.)

Der eigentliche Punkt ist, dass Sie richtig, auch in hinky Fällen wie diesem verhalten müssen: die Scoping und verbindliche Regeln sind einfach und gut definiert, und so etwas wie dies zu tun, die sieht verwirrend, ist nur eine Konsequenz von ihnen. Es ist praktisch, weil Sie mit lokalen lexikalischen Scripts mit let klarere Programme schreiben können, auch wenn es perverse Fälle gibt.

update Oh, ich habe einen Punkt weggelassen. Sie haben Recht, dass der Aufruf (+ a b) keine dauerhafte Wirkung hat, aber dann können Sie im allgemeinen Fall nicht davon ausgehen, dass das wahr wäre, und Sie können nicht feststellen, ob es wahr ist, indem Sie den Programmtext dort allein untersuchen. (Bedenken Sie: Dort könnte es andere Funktionen anstelle von "+" geben.) Wenn Sie jedoch davon ausgehen, dass Sie das richtige Ergebnis erhalten, ohne die verschiedenen let Klauseln auszuwerten, verstehen Sie nicht, was es versucht mach es noch.

6

tatsächlich können Sie nicht alle bis auf die letzte Anweisung "löschen", da die vorherigen Anweisungen nicht terminieren konnten. Zum Beispiel:

(define (func) (func)) 

(let() 
    (func) ;; does not return 
    1) 

Hier, wenn Sie (func) unevaluierten verlassen, erhalten Sie das falsche Ergebnis (die 1), während Sie nicht abbreche Berechnung erhalten sollte.

Ein weiteres Problem ist, dass Anruf/cc (Call-mit-Strom-Fortsetzung) (und ja, es gehört zu der funktionellen Teilmenge) verwendet werden kann, um tatsächlich Rückkehr aus der Berechnung von nicht-Schwanz Position, zum Beispiel:

(call-with-current-continuation 
    (lambda (ret) 
    (let() 
     (ret 3) 
     4))) 

die und nicht 4. Das ist nach wie vor rein funktionalen zurückkehren wird.

Hinweis BTW, dass (let() x y z) entspricht die Single-Statement Form (let() (begin x y z)) so die eigentliche Frage ist, ob Sie begin :)

brauchen