forked from okuoku/xitomatl
-
Notifications
You must be signed in to change notification settings - Fork 1
/
enumerators.sls
130 lines (116 loc) · 4.6 KB
/
enumerators.sls
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#!r6rs
;; Copyright 2009 Derick Eddington. My MIT-style license is in the file named
;; LICENSE from the original collection this file is distributed with.
;; Inspired by Oleg Kiselyov's "ideal enumerator":
;; http://okmij.org/ftp/papers/LL3-collections-enumerators.txt
;; http://okmij.org/ftp/Scheme/enumerators-callcc.html
;; http://okmij.org/ftp/Streams.html
;;
;; Do not mutate a collection while it is being enumerated by any of the
;; enumerators exported from this library. You can make your own enumerators
;; that support mutation during enumeration and they are guaranteed to work
;; with `fold' (if you add a specialization) and `fold/enumerator'.
(library (xitomatl enumerators)
(export
fold/enumerator fold fold-specialize!
list-enumerator procedure-enumerator
sequence-enumerator vector-enumerator string-enumerator
input-port-enumerator hashtable-enumerator)
(import
(rnrs)
(only (xitomatl define) define/? define/AV)
(only (xitomatl generics) define-generic/temporal))
(define/? (fold/enumerator (enum procedure?) coll (proc procedure?) . seeds)
(enum coll proc seeds))
(define/? (fold coll (proc procedure?) . seeds)
((enumerator coll) coll proc seeds))
(define/? (fold-specialize! (pred procedure?) (enum procedure?))
(enumerator-specialize! (list pred) (lambda (_) enum)))
(define-generic/temporal enumerator
(((_ (lambda (x) (or (pair? x) (null? x)))))
list-enumerator)
(((_ vector?))
vector-enumerator)
(((_ string?))
string-enumerator)
(((_ procedure?))
procedure-enumerator)
(((_ hashtable?))
hashtable-enumerator))
(define/AV (list-enumerator coll proc seeds)
;; fold-left which can be stopped.
(let loop ((seeds seeds) (h coll) (t coll))
(if (pair? h)
(let ((a (car h)) (h (cdr h)))
(if (pair? h)
(if (eq? h t)
(AV "circular list" coll)
(let ((b (car h)) (h (cdr h)) (t (cdr t)))
(let-values (((continue . a-seeds) (apply proc a seeds)))
(if continue
(let-values (((continue . b-seeds) (apply proc b a-seeds)))
(if continue
(loop b-seeds h t)
(apply values b-seeds)))
(apply values a-seeds)))))
(if (null? h)
(let-values (((_ . a-seeds) (apply proc a seeds)))
(apply values a-seeds))
(AV "not a proper list" coll))))
(if (null? h)
(apply values seeds)
(AV "not a proper list" coll)))))
(define/? (sequence-enumerator (len procedure?) (ref procedure?))
(lambda (coll proc seeds)
(let ((l (len coll)))
(let loop ((i 0) (seeds seeds))
(if (= i l)
(apply values seeds)
(let-values (((continue . next-seeds)
(apply proc (ref coll i) seeds)))
(if continue
(loop (+ 1 i) next-seeds)
(apply values next-seeds))))))))
(define vector-enumerator
(sequence-enumerator vector-length vector-ref))
(define string-enumerator
(sequence-enumerator string-length string-ref))
(define (procedure-enumerator coll proc seeds)
(let loop ((seeds seeds))
(call-with-values
coll
(case-lambda
((elem)
(let-values (((continue . next-seeds) (apply proc elem seeds)))
(if continue
(loop next-seeds)
(apply values next-seeds))))
(()
(apply values seeds))))))
(define/? (input-port-enumerator (reader procedure?))
(lambda (coll proc seeds)
;; NOTE: does not close the port
(let loop ((seeds seeds))
(let ((x (reader coll)))
(if (eof-object? x)
(apply values seeds)
(let-values (((continue . next-seeds) (apply proc x seeds)))
(if continue
(loop next-seeds)
(apply values next-seeds))))))))
(define (hashtable-enumerator coll proc seeds)
(let* ((keys (hashtable-keys coll))
(l (vector-length keys)))
(let loop ((i 0) (seeds seeds))
(if (= i l)
(apply values seeds)
(let-values (((continue . next-seeds)
(apply proc
(let* ((k (vector-ref keys i))
(v (hashtable-ref coll k #F)))
(cons k v))
seeds)))
(if continue
(loop (+ 1 i) next-seeds)
(apply values next-seeds)))))))
)