2016-03-30 6 views
0

Bitte zeigen Sie mir, wie Sie die SICP-Stream-Entzug-Funktion korrekt steuern.Wie fahren Sie diese SICP-Beispielfunktion?

(define (stream-cons a b) (cons a (delay b))) 
(define (stream-car s) (car s)) 
(define (stream-cdr s) (force (cdr s))) 

(define (stream-withdraw balance amount-stream) 
    (stream-cons 
    balance 
    (stream-withdraw (- balance (stream-car amount-stream)) (stream-cdr amount-stream)))) 

; Calling stream-withdraw in the following manner raises an exception. 
(stream-withdraw 100 (stream-cons 0 0)) 
; car: contract violation 
; expected: pair? 
; given: 0 

Ich nehme an, Mengenstrom sollte auf eine andere Weise konstruiert werden.

+0

Ich habe in SICP gefunden, dass Stream-Cons eine spezielle Form sein muss. Lassen Sie mich meine Frage modifizieren: Was ist der richtige Weg, Mengen-Stream zu konstruieren? Außerdem würde ich gerne die typische Art und Weise sehen, wie dieser Stream in nachfolgenden Aufrufen verwendet wird, um auf die funktionale Art und Weise zu streamen, während der Benutzer seine neuen Entnahmen eingibt. Ich sehe immer noch nicht das Schlüsselelement bei der Verwendung eines Streams, um den lokalen Zustand zu vermeiden. –

Antwort

1

Versuchen Sie, diese Definition verwenden:

(define-syntax stream-cons 
    (syntax-rules() 
    ((stream-cons head tail) 
    (cons head (delay tail))))) 

Da stream-cons unterschiedliche Bewertungsregeln erfordert, ist es nicht als normales Verfahren umgesetzt werden können - daher verwenden wir ein Makro. Aus dem gleichen Grund ist das delay Grundelement auch ein Makro.

+0

Vielen Dank für Ihre Antwort, die meine ursprüngliche Frage beantwortet. Könnten Sie vielleicht für einen OO-Programmierer skizzieren, wie Streams in einer einfachen Leseschleife angewendet werden können, um das Gleichgewicht für eine einzelne Person zu verwalten? Ich habe keine Ahnung, wie funktionales Programmieren Probleme ohne Zuweisung löst. –

+0

Vielleicht durch Schaffung eines Stroms von Werten für das Gleichgewicht? Ich bin ein wenig verstaubt in diesem Kapitel von SICP, aber IIRC das wird in dem Buch –

+0

erklärt Es war meine Hoffnung, dass das Kapitel über Streams mir helfen würde, dieses Problem zu verstehen. Leider wird die Anwendung des Balancestreams nicht angezeigt. Wenn Sie "einen Strom von Werten für das Gleichgewicht" sagen, klingt es für mich so, als ob es einen Strom gibt, der die Auszahlungen sammelt, aber dann sollte es veränderbar sein, oder? Ich bin wirklich verwirrt. –

1

Streams sind nicht wirklich Ersatz für mutierenden Zustand. Es ist eine Möglichkeit, die Evaluierung zu verzögern.

Ein Beispiel:

(define one-to-million 
    (let loop ((n #e1e6) (acc '())) 
    (if (zero? n) 
     acc 
     (loop (- n 1) (cons n acc))))) 

(define (list-square lst) 
    (map (lambda (x) (* x x)) lst)) 

(define (list-double lst) 
    (map (lambda (x) (+ x x)) lst)) 

(define (list-sqrt lst) 
    (map sqrt lst)) 

(take (list-sqrt (list-double (list-square one-to-million))) 5) 
; ==> (1.4142135623730951 2.8284271247461903 
;  4.242640687119285 5.656854249492381 7.0710678118654755) 

Wenn man sieht, was hier happnes Sie werden sehen, dass es bei jedem Schritt des Weges und am Ende verwendet nur die ersten eine neue Liste von Millionen Elemente macht 5 Ergebnisse. Eine Strom-Version:

(define (stream-take s n) 
    (if (zero? n) 
     '() 
     (cons (stream-car s) 
      (stream-take (stream-cdr s) (- n 1))))) 

(define (integers-starting-from n) 
    (stream-cons n (integers-starting-from (+ n 1)))) 

(define from1 (integers-starting-from 1)) ; infinite stream! 

(define (stream-map proc stream) 
    (stream-cons (proc (stream-car stream)) 
       (stream-map proc (stream-cdr stream)))) 

(define (stream-square stream) 
    (stream-map (lambda (x) (* x x)) stream)) 

(define (stream-double stream) 
    (stream-map (lambda (x) (+ x x)) stream)) 

(define (stream-sqrt stream) 
    (stream-map sqrt stream)) 

(stream-take (stream-sqrt (stream-double (stream-square from1))) 5) 
; ==> (1.4142135623730951 2.8284271247461903 
;  4.242640687119285 5.656854249492381 7.0710678118654755) 

In dieser Version wäre es vor dem Start auf den Platz des zweiten Elements jeden Schritt für das erste Element in dem Ergebnis tun, aber die Struktur fo das Programm sieht aus, als wenn Sie zuerst das Quadrat zu tun, dann der doppelte usw.

Eine vielleicht moderne Annäherung von diesem, das Listen aber alle Schritte in für jedes Element verwendet, sind gierig Wandler und Generatoren.

Wie für den Zustand halten Sie keine Streams dafür. Sie können eine Prozedur machen, dass es Rekursion bis fertig ist:

(let loop ((state '()) (input input)) 
    (if (input-empty? input) 
     state ; finished 
     (loop (process-input (input-get input) state) 
      (input-next input)))) 

Jetzt können wir geben diese eine völlig funktionelle Implementierung:

(define input '(1 2 3 4)) 
(define input-get car) 
(define input-next cdr) 
(define input-empty? null?) 
(define process-input cons) 

Oder wir könnten es einen schmutzigen Nebeneffekt Version machen:

(define input (current-input-port)) 
(define input-get read-line) 
(define input-next values) ; just return the port 
(define input-empty? (lambda (x) (eq? (peek-byte x) eof))) ; check if there is more to read 
(define process-input cons) 
+0

@AttilaKaroly Sie haben nach einem Beispiel gefragt und am Ende meiner Antwort habe ich eine. Ich benutze Streams in diesem Beispiel nicht, um zu zeigen, dass Streams keine Bedingung zum "Behalten"/"Aktualisieren" sind, aber wissen, dass das Anfordern von Benutzereingaben oder das Anzeigen von Ausgaben Nebenwirkungen sind und somit die Reinheit ruinieren. – Sylwester

Verwandte Themen