2016-07-20 2 views
2

In Schema können Sie Funktionen definieren, die einen Lambda-Ausdruck zurückgeben und sie verwenden, um neue Funktionen zu definieren. Zum Beispiel können Sie diesen CodeFunktion, die auf Lambda auswertet, kann nicht verwendet werden, um neue Funktion innerhalb des Bereichs zu definieren

(define (pow-iter base exp r) 
    (if (= exp 1) 
     r 
     (pow-iter base (- exp 1) (* base r)))) 

(define (pow exp) 
    (lambda (base) 
    (pow-iter base exp base))) 

(define cubic (pow 3)) 

(cubic 2) 

Wir haben hier schreiben eine Funktion pow, die die Exponenten als Argument nimmt und zu einer Lambda-Funktion, die auf die n-te Potenz der gegebenen Basis auswertet.

Wenn wir jedoch setzen, dass in einem Rahmen wie folgt aus:

(define (do-cubic x) 
    (define (pow-iter base exp r) 
    (if (= exp 1) 
     r 
     (pow-iter base (- exp 1) (* base r)))) 

    (define (pow exp) 
    (lambda (base) 
     (pow-iter base exp base))) 

    (define cubic (pow 3)) 

    (cubic x)) 

(do-cubic 2) 

Ich erhalte eine Fehler

pow: undefined; cannot use before initialization

Warum dieser Fehler auftreten und ist es eine Möglichkeit, es zu beheben, ohne die sich zu wandelnde Logik des Programms?

+0

in Racket siehe i t funktioniert. – Renzo

+0

@Renzo Du meinst, dass es in '#! Racket' funktioniert. In '#! R5rs', selbst unter RacketVM, sollte es fehlschlagen. Sie sind verschiedene Sprachen. – Sylwester

Antwort

3

Dieses Programm provoziert den gleichen Fehler:

#lang r5rs 
(let() 
    (define (foo x) (lambda (y) (+ 42 x))) 
    (define bar (foo 1)) 
    (bar 2)) 

Output: 
    foo: undefined; 
    cannot use before initialization 

Der Grund, warum Sie eine Fehlermeldung erhalten, dass „interne Definitionen“ in einen letrec Ausdruck neu geschrieben werden alle Bindungen wirksam sind, während ihre Ausgangswerte berechnet werden, Dies ermöglicht gegenseitig rekursive Definitionen.

(letrec ((foo (lambda (x) (lambda (y) (+ 42 x)))) 
     (bar (foo 1))) 
(bar 2)) 

In R5RS werden die Initialisierungsausdrücken in einer nicht spezifiziert ausgewertet. Dies bedeutet, dass im ersten obigen Snippet (define bar (foo 1)) vor (define (foo x) ...) ausgewertet werden kann. Mit anderen Worten, der Wert foo wird benötigt, bevor foo initialisiert wurde.

In Racket (#lang racket) interne Definitionen verwenden letrec* -semantics (dh die Initialisierungsausdrücken in der Reihenfolge ausgewertet werden sie im Code erscheinen. So läuft das Programm ohne Fehler.

Beachten Sie auch, dass die letrec in #lang racket entspricht zu dem, was letrec* tut in "R5RS" -implementations.

weitere Informationen über letrec vs letrec* die Einführung von http://www.cs.indiana.edu/~dyb/pubs/letrec-reloaded.pdf

Verwandte Themen