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)
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. –