global define
First off, Top-Level-Programme als durch einen anderen Teil der Umsetzung behandelt werden in einer Funktion ist und ein bereits definierte Variable ist nicht zulässig.
(define a 10)
(define a 20) ; ERROR: duplicate definition for identifier
Es kann vorkommen, dass es in einem REPL funktioniert, da es üblich ist, Sachen neu zu definieren, aber wenn Programme laufen das ist absolut verboten. In R5RS und vor dem, was passiert ist, ist es unterspezifiziert und war nicht wichtig, da die Spezifikation durch Verletzung es ist nicht mehr ein Scheme-Programm und Implementierer sind frei zu tun, was sie wollen. Das Ergebnis ist natürlich, dass viele unterspezifizierte Sachen ein implementierungsspezifisches Verhalten bekommen, das nicht tragbar oder stabil ist.
Lösung:
set!
mutiert Bindungen:
(define a 10)
(set! a 20)
define
in einer Lambda (Funktion, lassen, ...)
A define
in einem Lambda ist etwas ganz anderes, von völlig verschiedenen Teilen der Implementierung behandelt. Es wird von der Makro/speziellen Form behandelt lambda
so dass es zu einem letrec*
neu geschrieben wird
A letrec*
oder letrec
wird zur Herstellung von Funktionen verwendet rekursiv so die Namen zu der Zeit verfügbar sein müssen, die Ausdrücke ausgewertet werden. Aus diesem Grund, wenn Sie n
hat es bereits die n
beschattet Sie als Argument übergeben. Zusätzlich zu R6RS müssen Implementierer einen Fehler signalisieren, wenn eine Bindung ausgewertet wird, die noch nicht initialisiert wurde und das ist wahrscheinlich was passiert.Vor R6RS Implementierer waren frei zu tun, was sie wollten:
(define (func n)
(define n (+ n 1)) ; illegal since n hasn't got a value yet!
n)
Dies wird tatsächlich:
(define func
(lambda (n)
(let ((n 'undefined-blow-up-if-evaluated))
(let ((tmpn (+ n 1)))
(set! n tmpn))
n)))
Jetzt ein Compiler könnte sehen, dass es die Spezifikation zum Zeitpunkt der Kompilierung verletzt, aber viele Implementierungen weiß nicht, bevor es läuft.
(func 5) ; ==> 42
Perfekt fein Ergebnis in R5RS, wenn die Implementierer guten Geschmack in Bücher haben. Der Unterschied in der Version die nachweislich funktioniert, ist, dass dies nicht die Regel verstößt n
vor dem Körper Auswertung:
(define (func n)
(define n 5)
n)
wird:
(define func
(lambda (n)
(let ((n 'undefined-blow-up-if-evaluated))
(let ((tmpn 5)) ; n is never evaluated here!
(set! n tmpn))
n)))
Lösungen
Verwenden eines nicht widersprüchlicher Name
(define (func n)
(define new-n (+ n 1))
new-n)
Verwenden Sie let
. Es hat keine eigene Bindung, wenn der Ausdruck ausgewertet wird:
(define (func n)
(let ((n (+ n 1)))
n))