Skip to content

Commit 3d2b69d

Browse files
committed
First Draft Iteratee Library
0 parents  commit 3d2b69d

File tree

1 file changed

+235
-0
lines changed

1 file changed

+235
-0
lines changed

iteratees.sls

Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
#!r6rs
2+
(library (iteratees)
3+
(export make-chunk
4+
chunk?
5+
chunk-data
6+
stream?
7+
8+
make-done
9+
done?
10+
result
11+
make-cont
12+
cont?
13+
cont-k
14+
iteratee?
15+
16+
return
17+
>>=
18+
19+
peek
20+
head
21+
break
22+
heads
23+
24+
enum-eof
25+
enum-string
26+
enum-port
27+
>>>
28+
29+
run
30+
run-enumerator
31+
&divergent
32+
make-divergent-condition
33+
divergent-condition?
34+
)
35+
(import (rnrs)
36+
(srfi :13)
37+
(srfi :8)
38+
(prefix (monad maybe) m:))
39+
40+
;; Stream data type
41+
42+
(define-record-type chunk
43+
(fields data))
44+
45+
(define (stream? s)
46+
(or (chunk? s)
47+
(eof-object? s)))
48+
49+
(define-syntax stream-case
50+
(syntax-rules (chunk eof)
51+
((stream-case stream-expr ((chunk) empty-chunk-case) ((chunk s) chunk-case) ((eof) empty-case))
52+
(let ((stream stream-expr))
53+
(if (chunk? stream)
54+
(let ((s (chunk-data stream)))
55+
(if (string-null? s)
56+
empty-chunk-case
57+
chunk-case))
58+
empty-case)))))
59+
60+
;; Iteratee data type
61+
62+
(define-record-type done
63+
(fields (immutable result result)))
64+
65+
(define-record-type cont
66+
;; k : Stream -> Iteratee + Stream
67+
(fields k))
68+
69+
(define (iteratee? x)
70+
(or (done? x)
71+
(cont? x)))
72+
73+
;; utilities
74+
(define empty-chunk (make-chunk ""))
75+
76+
(define (doneM s)
77+
(values (make-done s) empty-chunk))
78+
79+
(define (contM s)
80+
(values (make-cont s) empty-chunk))
81+
82+
(define (string-break p s)
83+
(define idx (string-index s p))
84+
(if idx
85+
(values (string-take s idx)
86+
(string-drop s idx))
87+
(values s "")))
88+
89+
(define (continue i v)
90+
((cont-k i) v))
91+
92+
(define buffer-size 1024)
93+
94+
;; Iteratee Monad Instance
95+
96+
(define return make-done)
97+
98+
(define (>>= m f)
99+
(define (do-case i s)
100+
(if (done? i)
101+
(let ((new-i (f (result i))))
102+
(if (cont? new-i)
103+
(continue new-i s)
104+
(values new-i s)))
105+
(values (>>= i f) s)))
106+
(if (done? m)
107+
(f (result m))
108+
(make-cont
109+
(lambda (x)
110+
(receive (i s) (continue m x)
111+
(do-case i s))))))
112+
113+
;; Iteratees
114+
115+
(define peek
116+
(letrec ((step (lambda (stream)
117+
(stream-case stream
118+
((chunk)
119+
(values peek stream))
120+
((chunk s)
121+
(values (make-done (m:just (string-ref s 0))) stream))
122+
((eof)
123+
(values (make-done (m:nothing)) stream))))))
124+
(make-cont step)))
125+
126+
(define head
127+
(letrec ((step (lambda (stream)
128+
(stream-case stream
129+
((chunk) (values peek stream))
130+
((chunk s)
131+
(values (make-done (m:just (string-ref s 0)))
132+
(string-drop s 1)))
133+
((eof)
134+
(values (make-done (m:nothing)) stream))))))
135+
(make-cont step)))
136+
137+
(define (break pred?)
138+
(define (step before)
139+
(lambda (stream)
140+
(stream-case stream
141+
((chunk) (contM (step before)))
142+
((chunk s)
143+
(receive (prefix suffix) (string-break pred? s)
144+
(if (string-null? suffix)
145+
(contM (step (string-append before prefix)))
146+
(values (make-done (string-append before prefix))
147+
(make-chunk suffix)))))
148+
((eof)
149+
(values (make-done before) stream)))))
150+
(make-cont (step "")))
151+
152+
(define (heads prefix)
153+
(define (loop count cs)
154+
(if (null? cs)
155+
(return count)
156+
(make-cont (step count cs))))
157+
(define (step count cs)
158+
(lambda (stream)
159+
(stream-case stream
160+
((chunk)
161+
(values (loop count cs) stream))
162+
((chunk s)
163+
(if (null? cs)
164+
(values (make-done count) stream)
165+
(if (char=? (car cs) (string-ref s 0))
166+
((step (+ 1 count) (cdr cs))
167+
(make-chunk (string-drop s 1)))
168+
(values (make-done count) stream))))
169+
((eof)
170+
(values (make-done count) stream)))))
171+
(loop 0 (string->list prefix)))
172+
173+
174+
;; enumerators
175+
(define (enum-eof iter)
176+
(if (cont? iter)
177+
(receive (iter* stream) (continue iter (eof-object))
178+
iter*)
179+
iter))
180+
181+
(define (enum-string string)
182+
(lambda (iter)
183+
(if (cont? iter)
184+
(receive (iter* stream) (continue iter (make-chunk string))
185+
iter*)
186+
iter)))
187+
188+
(define (enum-port port)
189+
(define (loop iter)
190+
(if (cont? iter)
191+
(let ((str (get-string-n port buffer-size)))
192+
(if (eof-object? str)
193+
iter
194+
(receive (iter s) (continue iter (make-chunk str))
195+
(loop iter))))
196+
iter))
197+
loop)
198+
199+
(define >>>
200+
(let ((join (lambda (g f)
201+
(lambda (x)
202+
(f (g x))))))
203+
(case-lambda
204+
(() (lambda (x) x))
205+
((a) a)
206+
((a b) (join a b))
207+
((a b . c)
208+
(fold-left join a (cons b c))))))
209+
210+
211+
;; running iteratees
212+
213+
(define (run iteratee)
214+
(if (done? iteratee)
215+
(result iteratee)
216+
(let ((iter2 (continue iteratee (eof-object))))
217+
(if (done? iter2)
218+
(result iter2)
219+
(diverges 'run "Iteratee diverges on eof" iteratee)))))
220+
221+
(define (run-enumerator enum iteratee)
222+
(run (enum iteratee)))
223+
224+
(define (diverges who message irritant)
225+
(raise
226+
(condition (make-divergent-condition)
227+
(make-who-condition who)
228+
(make-message-condition message)
229+
(make-irritants-condition irritant))))
230+
231+
(define-condition-type &divergent &error
232+
make-divergent-condition
233+
divergent-condition?)
234+
235+
)

0 commit comments

Comments
 (0)