2016-06-18 17 views
2

Nach der Lektüre des „Warum sollte das FUNARG Problem die Umwelt Problem aufgerufen werden:“ Ich habe mir eine Frage gestellt: Was passiert, wenn wir eine Funktion verbieten zu definieren, dass eine Schließung nicht schaffen kann, das heißtSprache ohne freie Variablen

(define (foo x) (+ a x)) 

wird nicht auf der obersten Ebene zugelassen werden (weil es keine Umgebung zu schließen, ist vorbei ein enthält), während

(define (bar a) (lambda (x) (+ a x))) 

erlaubt ist, weil zurück Lambda einen Verschluss schaffen. Zwei Fragen hier:
1. Wie kann dies die Ausdruckskraft der Sprache beeinträchtigen? Gibt es bestimmte Funktionen, die mit einer solchen Einschränkung nicht verfügbar sind? Kann jemand ein Beispiel geben, wenn das Definieren von Funktionen mit freien Variablen nützlich sein kann?
2. Bedeutet dies, dass alle Umgebungsvariablen in Closures jetzt statische und vorhersagbare Offsets haben?

+0

Schema führte lexikalische Scoping und Verschlüsse zu Lisp ein, die das "Umweltproblem" effektiv lösten **. Moderne Lisps wie Scheme/Racket, Common Lisp und Clojure verwenden lexikalisches Scoping, was im Grunde so funktioniert, wie Sie es beschreiben. Emacs Lisp ist jedoch ein interessantes Beispiel für ein Lisp, das immer noch verwendet wird, aber standardmäßig kein lexikalisches Scoping verwendet. –

+1

Sie sollten sich die hyperstatische globale Umgebung ansehen (siehe z. B. http://c2.com/cgi/wiki?HyperStaticGlobalEnvironment), die verwendet wird, wenn ich mich in OCaml nicht irre. Sogar Neudefinitionen auf globaler Ebene überschatten vorhandene Bindungen und ändern nicht die Semantik des vorhandenen Codes, im Gegensatz zu dynamischen Umgebungen wie Common Lisp, wo Sie Funktionen leicht neu definieren können. – coredump

+1

da * ist * eine Umgebung zu schließen - die "globale"/"oberste Ebene" Umgebung. die Frage ist, wie verhält es sich bei Neudefinitionen seiner Variablen - verändert es die Bindungen (d. h. es ändert alle vorherigen Verweise auf diese) oder schattiert sie (d. h. sie treten von nun an in Kraft). Die andere Frage ist, was in der REPL und/oder in kompilierten Dateien getan wird ... –

Antwort

1

Wie gesagt von Will Ness und tfb, gibt es eine globale Umgebung. In Ihrem Ausdruck sind sowohl + als auch a freie Variablen. Entscheidend ist, ob a in Ihrer globalen Umgebung existiert oder nicht, wenn Sie f definieren. Außerdem ist "frei" oder "gebunden" eine relative Vorstellung.

Es ist wenig sinnvoll, auf eine lexikalische Variable zu verweisen, die in keiner Umgebung gebunden ist. Das einzige Beispiel, an das ich denken kann, ist an die Metaprogrammierung gebunden, aber das ist nicht wirklich relevant, weil Sie in diesem Fall Code nur als Daten manipulieren. Wenn Sie schließlich ein Formular erstellen und es kompilieren oder auswerten, haben Sie immer noch einen lexikalischen Geltungsbereich und dann müssen alle Ihre Symbole in eine bekannte Variable aufgelöst werden. Mit speziellen Variablen in Common Lisp oder Emacs dynamisch-Standardvariablen, ist es sinnvoll, auf freie Variablen verweisen. In Emacs können Sie sogar auf Variablen verweisen, die nicht ohne Warnungen deklariert sind.

Wie kann dies die Ausdruckskraft der Sprache beeinflussen?

Also, wenn Sie freie Variablen (nicht gebunden in jedem lexikalischen Gültigkeitsbereich) nicht zulassen, sind Sie im Grunde Variablen mit dynamischem Umfang disallowing (in Common Lisp, werden sie definiert unbestimmten Umfang und dynamischen Umfang hat mit). Du verlierst an Ausdruckskraft. Dies ist beispielsweise in OCaml der Fall. Sie können jedoch weiterhin eine Bibliothek definieren, um sie zu simulieren, wie in Delimited Dynamic Binding und implementation gezeigt.

OCaml bietet eine hyper-static global environment an, die nicht nur den lexikalischen Geltungsbereich, sondern auch das Ändern bestehender Bindungen verbietet.

# let a = 10;; 
val a : int = 10 

# let f() = a;; 
val f : unit -> int = <fun> 

# let a = 20;; 
val a : int = 20 

# f() 
- : int = 10 

hier oberhalb der zweiten a Schatten die vorherige, aber f bezieht sich weiterhin auf die vorherige a. Dies ist auch der Fall für Funktionen, weshalb es ein rec Schlüsselwort gibt, um rekursive und gegenseitig rekursive Funktionen zu definieren. Dies ist ein anderer Ansatz als Lisp, der bemerkenswert ist, um die meisten Dinge zur Laufzeit neu zu definieren.

Bedeutet dies, dass alle Umgebungsvariablen in Closures jetzt statische und vorhersagbare Offsets haben?

Lexical Umfang erlaubt Variablen zu kompilieren nach unten zu festen Standorten. Ob dies geschieht oder nicht, hängt von Ihren Tools ab. Zum Beispiel könnte Ihre Umgebung in einem Interpreter in einer Laufzeitdatenstruktur gehalten werden.