Next: srfi streams examples pitfalls, Previous: srfi streams examples persistent, Up: srfi streams examples [Index]
The final example is a lazy dictionary, where definitions and uses may occur in any order; in particular, uses may precede their corresponding definitions. This is a common problem.
Many programming languages allow procedures to be used before they are defined. Macro processors must collect definitions and emit uses of text in order. An assembler needs to know the address that a linker will subsequently give to variables. The usual method is to make two passes over the data, collecting the definitions on the first pass and emitting the uses on the second pass. But Chris Reade shows how streams allow the dictionary to be built lazily, so that only a single pass is needed. Consider a stream of requests:
(define requests (stream '(get 3) '(put 1 "a") ; use follows definition '(put 3 "c") ; use precedes definition '(get 1) '(get 2) '(put 2 "b") ; use precedes definition '(put 4 "d"))) ; unused definition
We want a procedure that will display cab, which is the result of
(get 3)
, (get 1)
, and (get 2)
, in order. We first
separate the request stream into gets and puts:
(define (get? obj) (eq? (car obj) 'get)) (define-stream (gets strm) (stream-map cadr (stream-filter get? strm))) (define-stream (puts strm) (stream-map cdr (stream-remove get? strm)))
Now, run-dict
inserts each element of the puts stream into a lazy
dictionary, represented as a stream of key/value pairs (an association
stream), then looks up each element of the gets stream with
stream-assoc
:
(define-stream (run-dict requests) (let ([dict (build-dict (puts requests))]) (stream-map (rsec stream-assoc dict) (gets requests)))) (define (stream-assoc key dict) (cond [(stream-null? dict) #f] [(equal? key (car (stream-car dict))) (stream-car dict)] [else (stream-assoc key (stream-cdr dict))]))
dict is created in the let
, but nothing is initially added
to it. Each time stream-assoc
performs a lookup, enough of
dict is built to satisfy the lookup, but no more. We are assuming
that each item is defined once and only once. All that is left is to
define the procedure that inserts new items into the dictionary, lazily:
(define-stream (build-dict puts) (if (stream-null? puts) stream-null (stream-cons (stream-car puts) (build-dict (stream-cdr puts)))))
Now we can run the requests and print the result:
(stream-for-each display (stream-map cadr (run-dict requests)))
The (put 4 "d")
definition is never added to the dictionary
because it is never needed.
Next: srfi streams examples pitfalls, Previous: srfi streams examples persistent, Up: srfi streams examples [Index]