-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathcomparator.sld
246 lines (216 loc) · 9.3 KB
/
comparator.sld
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
;; Comparators (SRFI 128), polyfilled for Kawa and bugfixed for other Schemes.
;;
;; Polyfills taken from the SRFI 128 implementation at
;; https://srfi.schemers.org/srfi-128/srfi-128.html
;;
;; Defines a bunch of extra comparators as well.
;; Some are taken from SRFI 162 or 114, others are original.
;;
;; Also exports `hash-lambda`, a `lambda` that takes and ignores a 2nd argument.
;; R7RS implementations don't agree on the arity of SRFI 128 hash functions,
;; so this is necessary for compatibility.
(define-library (schemepunk comparator)
(export comparator? comparator-ordered? comparator-hashable?
make-comparator
make-pair-comparator make-list-comparator make-vector-comparator
make-eq-comparator make-eqv-comparator make-equal-comparator
boolean-hash char-hash char-ci-hash
string-hash string-ci-hash symbol-hash number-hash
make-default-comparator default-hash comparator-register-default!
comparator-type-test-predicate comparator-equality-predicate
comparator-ordering-predicate comparator-hash-function
comparator-test-type comparator-check-type comparator-hash
hash-bound hash-salt
=? <? >? <=? >=?
comparator-if<=>)
(export comparator-max comparator-min
comparator-max-in-list comparator-min-in-list
default-comparator boolean-comparator real-comparator
fixnum-comparator char-comparator char-ci-comparator
string-comparator string-ci-comparator
pair-comparator list-comparator vector-comparator
eq-comparator eqv-comparator equal-comparator)
(export make-sum-comparator symbol-comparator number-comparator
hash-lambda identity-hash identity<?)
(import (scheme base)
(scheme case-lambda)
(scheme char)
(scheme inexact)
(scheme complex)
(scheme lazy)
(schemepunk syntax)
(schemepunk list))
(cond-expand
((or chicken chibi larceny)
(import (srfi 128)
(rename (only (srfi 69) hash-by-identity)
(hash-by-identity identity-hash))))
((or (library (scheme comparator)) (library (srfi 128)))
(cond-expand
((library (scheme comparator))
(import (except (scheme comparator) make-pair-comparator
make-list-comparator
make-vector-comparator)))
(else
(import (except (srfi 128) make-pair-comparator
make-list-comparator
make-vector-comparator))))
(cond-expand
((library (srfi 69))
(import (rename (only (srfi 69) hash-by-identity)
(hash-by-identity identity-hash))))
((library (srfi 126))
(import (rename (only (srfi 126) equal-hash)
(equal-hash identity-hash))))
((library (std srfi 125))
(import (rename (only (std srfi 125) hash-by-identity)
(hash-by-identity identity-hash)))))
(include "polyfills/128.universals.scm"))
(else
(cond-expand
((library (srfi 126))
(import (only (srfi 126) equal-hash string-hash string-ci-hash)))
((library (srfi 69))
(import (rename (only (srfi 69) hash-by-identity)
(hash-by-identity equal-hash))
(only (srfi 69) string-hash string-ci-hash))))
(include "polyfills/128.body1.scm")
(include "polyfills/128.universals.scm")
(include "polyfills/128.body2.scm")
(begin (define identity-hash equal-hash))))
(begin
(define-syntax hash-lambda
(syntax-rules ()
((hash-lambda (x) . body)
(case-lambda
((x) . body)
((x y) . body)))
((hash-lambda (x y) . body)
(case-lambda
((x) (let ((y 0)) . body))
((x y) . body))))))
(cond-expand
((and (not chicken) (library (srfi 143)))
(import (srfi 143))
(begin
(define fixnum-comparator
(make-comparator fixnum? fx=? fx<? (hash-lambda (x) x)))))
(gerbil
(import (std srfi 143))
(begin
(define fixnum-comparator
(make-comparator fixnum? fx=? fx<? (hash-lambda (x) x)))))
(else
(begin
(define fixnum-comparator
(make-comparator
(λ x (and (number? x) (exact? x) (integer? x)))
=
<
(hash-lambda (x) x))))))
(cond-expand
((and (not chicken) (not gauche) (library (srfi 162)))
(import (srfi 162)))
((and (not chicken) (library (srfi 114)))
(import (only (srfi 114)
comparator-max comparator-min
default-comparator boolean-comparator real-comparator
char-comparator char-ci-comparator
string-comparator string-ci-comparator
pair-comparator list-comparator vector-comparator
eq-comparator eqv-comparator equal-comparator
symbol-comparator number-comparator))
(begin
(define (comparator-max-in-list comp xs)
(apply comparator-max comp xs))
(define (comparator-min-in-list comp xs)
(apply comparator-min comp xs))))
(else
(begin
(cond-expand
((or chicken (library (srfi 128)) (library (scheme comparator)))
; If the polyfill was not loaded, define symbol<? here
(define (symbol<? x y)
(string<? (symbol->string x) (symbol->string y))))
(else))
(define (comparator-max-in-list comp list)
(let ((< (comparator-ordering-predicate comp)))
(let loop ((max (car list)) (list (cdr list)))
(if (null? list)
max
(if (< max (car list))
(loop (car list) (cdr list))
(loop max (cdr list)))))))
(define (comparator-min-in-list comp list)
(let ((< (comparator-ordering-predicate comp)))
(let loop ((min (car list)) (list (cdr list)))
(if (null? list)
min
(if (< min (car list))
(loop min (cdr list))
(loop (car list) (cdr list)))))))
(define (comparator-max comp . args)
(comparator-max-in-list comp args))
(define (comparator-min comp . args)
(comparator-min-in-list comp args))
(define-syntax lazy-comparator
(syntax-rules ()
((_ cmp)
(let1 wrapped (delay cmp)
(make-comparator
(cut comparator-test-type (force wrapped) <>)
(cut =? (force wrapped) <> <>)
(cut <? (force wrapped) <> <>)
(cut comparator-hash (force wrapped) <>))))))
(define default-comparator
(lazy-comparator (make-default-comparator)))
(define boolean-comparator
(make-comparator boolean? boolean=? (λ(x y) (and (not x) y)) (hash-lambda (x) (if x 1 0))))
(define real-comparator
(make-comparator real? = < number-hash))
(define char-comparator
(make-comparator char? char=? char<? char-hash))
(define char-ci-comparator
(make-comparator char? char-ci=? char-ci<? char-ci-hash))
(define string-comparator
(make-comparator string? string=? string<? string-hash))
(define string-ci-comparator
(make-comparator string? string-ci=? string-ci<? string-ci-hash))
(define symbol-comparator
(make-comparator symbol? symbol=? symbol<? symbol-hash))
(define number-comparator
(make-comparator number? = < number-hash))
(define pair-comparator
(lazy-comparator (make-pair-comparator default-comparator default-comparator)))
(define list-comparator
(lazy-comparator (make-list-comparator default-comparator list? null? car cdr)))
(define vector-comparator
(lazy-comparator (make-vector-comparator default-comparator vector? vector-length vector-ref)))
(define eq-comparator (lazy-comparator (make-eq-comparator)))
(define eqv-comparator (lazy-comparator (make-eqv-comparator)))
(define equal-comparator (lazy-comparator (make-equal-comparator))))))
(begin
(define (make-sum-comparator . comparators)
(define tests (map comparator-type-test-predicate comparators))
(make-comparator
(λ x (any (cut <> x) tests))
(λ(x y)
(let ((cmp-x (find (cut comparator-test-type <> x) comparators))
(cmp-y (find (cut comparator-test-type <> y) comparators)))
(and cmp-x (eq? cmp-x cmp-y) (=? cmp-x x y))))
(λ(x y)
(let ((ix (list-index (cut <> x) tests))
(iy (list-index (cut <> y) tests)))
(cond
((< ix iy) #t)
((> ix iy) #f)
(else (<? (list-ref comparators ix) x y)))))
(hash-lambda (x)
(let* ((i (list-index (cut <> x) tests))
(cmp (list-ref comparators i))
(hash (comparator-hash cmp x)))
(if (zero? i)
hash
(modulo (+ i (* hash 33)) (hash-bound)))))))
(define (identity<? x y)
(< (identity-hash x) (identity-hash y)))))