128.body1.scm 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. ;;; Copyright (C) John Cowan (2015). All Rights Reserved.
  2. ;;;
  3. ;;; Permission is hereby granted, free of charge, to any person
  4. ;;; obtaining a copy of this software and associated documentation
  5. ;;; files (the "Software"), to deal in the Software without
  6. ;;; restriction, including without limitation the rights to use,
  7. ;;; copy, modify, merge, publish, distribute, sublicense, and/or
  8. ;;; sell copies of the Software, and to permit persons to whom the
  9. ;;; Software is furnished to do so, subject to the following
  10. ;;; conditions:
  11. ;;;
  12. ;;; The above copyright notice and this permission notice shall be
  13. ;;; included in all copies or substantial portions of the Software.
  14. ;;;
  15. ;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  16. ;;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  17. ;;; OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  18. ;;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  19. ;;; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  20. ;;; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  21. ;;; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  22. ;;; OTHER DEALINGS IN THE SOFTWARE.
  23. ;;;; Main part of the SRFI 114 reference implementation
  24. ;;; "There are two ways of constructing a software design: One way is to
  25. ;;; make it so simple that there are obviously no deficiencies, and the
  26. ;;; other way is to make it so complicated that there are no *obvious*
  27. ;;; deficiencies." --Tony Hoare
  28. ;;; Syntax (because syntax must be defined before it is used, contra Dr. Hardcase)
  29. ;; Arithmetic if
  30. (define-syntax comparator-if<=>
  31. (syntax-rules ()
  32. ((if<=> a b less equal greater)
  33. (comparator-if<=> (make-default-comparator) a b less equal greater))
  34. ((comparator-if<=> comparator a b less equal greater)
  35. (cond
  36. ((=? comparator a b) equal)
  37. ((<? comparator a b) less)
  38. (else greater)))))
  39. ;; Upper bound of hash functions is 2^25-1
  40. (define-syntax hash-bound
  41. (syntax-rules ()
  42. ((hash-bound) 33554432)))
  43. (define %salt% (make-parameter 16064047))
  44. (define-syntax hash-salt
  45. (syntax-rules ()
  46. ((hash-salt) (%salt%))))
  47. (define-syntax with-hash-salt
  48. (syntax-rules ()
  49. ((with-hash-salt new-salt hash-func obj)
  50. (parameterize ((%salt% new-salt)) (hash-func obj)))))
  51. ;;; Definition of comparator records with accessors and basic comparator
  52. (define-record-type comparator
  53. (make-raw-comparator type-test equality ordering hash ordering? hash?)
  54. comparator?
  55. (type-test comparator-type-test-predicate)
  56. (equality comparator-equality-predicate)
  57. (ordering comparator-ordering-predicate)
  58. (hash comparator-hash-function)
  59. (ordering? comparator-ordered?)
  60. (hash? comparator-hashable?))
  61. ;; Public constructor
  62. (define (make-comparator type-test equality ordering hash)
  63. (make-raw-comparator
  64. (if (eq? type-test #t) (lambda (x) #t) type-test)
  65. (if (eq? equality #t) (lambda (x y) (eqv? (ordering x y) 0)) equality)
  66. (if ordering ordering (lambda (x y) (error "ordering not supported")))
  67. (if hash hash (lambda (x y) (error "hashing not supported")))
  68. (if ordering #t #f)
  69. (if hash #t #f)))
  70. ;;; Invokers
  71. ;; Invoke the test type
  72. (define (comparator-test-type comparator obj)
  73. ((comparator-type-test-predicate comparator) obj))
  74. ;; Invoke the test type and throw an error if it fails
  75. (define (comparator-check-type comparator obj)
  76. (if (comparator-test-type comparator obj)
  77. #t
  78. (error "comparator type check failed" comparator obj)))
  79. ;; Invoke the hash function
  80. (define (comparator-hash comparator obj)
  81. ((comparator-hash-function comparator) obj))
  82. ;;; Comparison predicates
  83. ;; Binary versions for internal use
  84. (define (binary=? comparator a b)
  85. ((comparator-equality-predicate comparator) a b))
  86. (define (binary<? comparator a b)
  87. ((comparator-ordering-predicate comparator) a b))
  88. (define (binary>? comparator a b)
  89. (binary<? comparator b a))
  90. (define (binary<=? comparator a b)
  91. (not (binary>? comparator a b)))
  92. (define (binary>=? comparator a b)
  93. (not (binary<? comparator a b)))
  94. ;; General versions for export
  95. (define (=? comparator a b . objs)
  96. (let loop ((a a) (b b) (objs objs))
  97. (and (binary=? comparator a b)
  98. (if (null? objs) #t (loop b (car objs) (cdr objs))))))
  99. (define (<? comparator a b . objs)
  100. (let loop ((a a) (b b) (objs objs))
  101. (and (binary<? comparator a b)
  102. (if (null? objs) #t (loop b (car objs) (cdr objs))))))
  103. (define (>? comparator a b . objs)
  104. (let loop ((a a) (b b) (objs objs))
  105. (and (binary>? comparator a b)
  106. (if (null? objs) #t (loop b (car objs) (cdr objs))))))
  107. (define (<=? comparator a b . objs)
  108. (let loop ((a a) (b b) (objs objs))
  109. (and (binary<=? comparator a b)
  110. (if (null? objs) #t (loop b (car objs) (cdr objs))))))
  111. (define (>=? comparator a b . objs)
  112. (let loop ((a a) (b b) (objs objs))
  113. (and (binary>=? comparator a b)
  114. (if (null? objs) #t (loop b (car objs) (cdr objs))))))
  115. ;;; Simple ordering and hash functions
  116. (define (boolean<? a b)
  117. ;; #f < #t but not otherwise
  118. (and (not a) b))
  119. (define (boolean-hash obj)
  120. (if obj (%salt%) 0))
  121. (define (char-hash obj)
  122. (modulo (* (%salt%) (char->integer obj)) (hash-bound)))
  123. (define (char-ci-hash obj)
  124. (modulo (* (%salt%) (char->integer (char-foldcase obj))) (hash-bound)))
  125. (define (number-hash obj)
  126. (cond
  127. ((nan? obj) (%salt%))
  128. ((and (infinite? obj) (positive? obj)) (* 2 (%salt%)))
  129. ((infinite? obj) (* (%salt%) 3))
  130. ((real? obj) (abs (exact (round obj))))
  131. (else (+ (number-hash (real-part obj)) (number-hash (imag-part obj))))))
  132. ;; Lexicographic ordering of complex numbers
  133. (define (complex<? a b)
  134. (if (= (real-part a) (real-part b))
  135. (< (imag-part a) (imag-part b))
  136. (< (real-part a) (real-part b))))
  137. (define (string-ci-hash obj)
  138. (string-hash (string-foldcase obj)))
  139. (define (symbol<? a b) (string<? (symbol->string a) (symbol->string b)))
  140. (define (symbol-hash obj)
  141. (string-hash (symbol->string obj)))
  142. ;;; Wrapped equality predicates
  143. ;;; These comparators don't have ordering functions.
  144. (define (make-eq-comparator)
  145. (make-comparator #t eq? #f default-hash))
  146. (define (make-eqv-comparator)
  147. (make-comparator #t eqv? #f default-hash))
  148. (define (make-equal-comparator)
  149. (make-comparator #t equal? #f default-hash))
  150. ;;; Sequence ordering and hash functions
  151. ;; The hash functions are based on djb2, but
  152. ;; modulo 2^25 instead of 2^32 in hopes of sticking to fixnums.
  153. (define (make-hasher)
  154. (let ((result (%salt%)))
  155. (case-lambda
  156. (() result)
  157. ((n) (set! result (+ (modulo (* result 33) (hash-bound)) n))
  158. result))))
  159. ;;; Pair comparator
  160. (define (make-pair-comparator car-comparator cdr-comparator)
  161. (make-comparator
  162. (make-pair-type-test car-comparator cdr-comparator)
  163. (make-pair=? car-comparator cdr-comparator)
  164. (make-pair<? car-comparator cdr-comparator)
  165. (make-pair-hash car-comparator cdr-comparator)))
  166. (define (make-pair-type-test car-comparator cdr-comparator)
  167. (lambda (obj)
  168. (and (pair? obj)
  169. (comparator-test-type car-comparator (car obj))
  170. (comparator-test-type cdr-comparator (cdr obj)))))
  171. (define (make-pair=? car-comparator cdr-comparator)
  172. (lambda (a b)
  173. (and ((comparator-equality-predicate car-comparator) (car a) (car b))
  174. ((comparator-equality-predicate cdr-comparator) (cdr a) (cdr b)))))
  175. (define (make-pair<? car-comparator cdr-comparator)
  176. (lambda (a b)
  177. (if (=? car-comparator (car a) (car b))
  178. (<? cdr-comparator (cdr a) (cdr b))
  179. (<? car-comparator (car a) (car b)))))
  180. (define (make-pair-hash car-comparator cdr-comparator)
  181. (lambda (obj)
  182. (let ((acc (make-hasher)))
  183. (acc (comparator-hash car-comparator (car obj)))
  184. (acc (comparator-hash cdr-comparator (cdr obj)))
  185. (acc))))
  186. ;;; List comparator
  187. ;; Cheap test for listness
  188. (define (norp? obj) (or (null? obj) (pair? obj)))
  189. (define (make-list-comparator element-comparator type-test empty? head tail)
  190. (make-comparator
  191. (make-list-type-test element-comparator type-test empty? head tail)
  192. (make-list=? element-comparator type-test empty? head tail)
  193. (make-list<? element-comparator type-test empty? head tail)
  194. (make-list-hash element-comparator type-test empty? head tail)))
  195. (define (make-list-type-test element-comparator type-test empty? head tail)
  196. (lambda (obj)
  197. (and
  198. (type-test obj)
  199. (let ((elem-type-test (comparator-type-test-predicate element-comparator)))
  200. (let loop ((obj obj))
  201. (cond
  202. ((empty? obj) #t)
  203. ((not (elem-type-test (head obj))) #f)
  204. (else (loop (tail obj)))))))))
  205. (define (make-list=? element-comparator type-test empty? head tail)
  206. (lambda (a b)
  207. (let ((elem=? (comparator-equality-predicate element-comparator)))
  208. (let loop ((a a) (b b))
  209. (cond
  210. ((and (empty? a) (empty? b) #t))
  211. ((empty? a) #f)
  212. ((empty? b) #f)
  213. ((elem=? (head a) (head b)) (loop (tail a) (tail b)))
  214. (else #f))))))
  215. (define (make-list<? element-comparator type-test empty? head tail)
  216. (lambda (a b)
  217. (let ((elem=? (comparator-equality-predicate element-comparator))
  218. (elem<? (comparator-ordering-predicate element-comparator)))
  219. (let loop ((a a) (b b))
  220. (cond
  221. ((and (empty? a) (empty? b) #f))
  222. ((empty? a) #t)
  223. ((empty? b) #f)
  224. ((elem=? (head a) (head b)) (loop (tail a) (tail b)))
  225. ((elem<? (head a) (head b)) #t)
  226. (else #f))))))
  227. (define (make-list-hash element-comparator type-test empty? head tail)
  228. (lambda (obj)
  229. (let ((elem-hash (comparator-hash-function element-comparator))
  230. (acc (make-hasher)))
  231. (let loop ((obj obj))
  232. (cond
  233. ((empty? obj) (acc))
  234. (else (acc (elem-hash (head obj))) (loop (tail obj))))))))
  235. ;;; Vector comparator
  236. (define (make-vector-comparator element-comparator type-test length ref)
  237. (make-comparator
  238. (make-vector-type-test element-comparator type-test length ref)
  239. (make-vector=? element-comparator type-test length ref)
  240. (make-vector<? element-comparator type-test length ref)
  241. (make-vector-hash element-comparator type-test length ref)))
  242. (define (make-vector-type-test element-comparator type-test length ref)
  243. (lambda (obj)
  244. (and
  245. (type-test obj)
  246. (let ((elem-type-test (comparator-type-test-predicate element-comparator))
  247. (len (length obj)))
  248. (let loop ((n 0))
  249. (cond
  250. ((= n len) #t)
  251. ((not (elem-type-test (ref obj n))) #f)
  252. (else (loop (+ n 1)))))))))
  253. (define (make-vector=? element-comparator type-test length ref)
  254. (lambda (a b)
  255. (and
  256. (= (length a) (length b))
  257. (let ((elem=? (comparator-equality-predicate element-comparator))
  258. (len (length b)))
  259. (let loop ((n 0))
  260. (cond
  261. ((= n len) #t)
  262. ((elem=? (ref a n) (ref b n)) (loop (+ n 1)))
  263. (else #f)))))))
  264. (define (make-vector<? element-comparator type-test length ref)
  265. (lambda (a b)
  266. (cond
  267. ((< (length a) (length b)) #t)
  268. ((> (length a) (length b)) #f)
  269. (else
  270. (let ((elem=? (comparator-equality-predicate element-comparator))
  271. (elem<? (comparator-ordering-predicate element-comparator))
  272. (len (length a)))
  273. (let loop ((n 0))
  274. (cond
  275. ((= n len) #f)
  276. ((elem=? (ref a n) (ref b n)) (loop (+ n 1)))
  277. ((elem<? (ref a n) (ref b n)) #t)
  278. (else #f))))))))
  279. (define (make-vector-hash element-comparator type-test length ref)
  280. (lambda (obj)
  281. (let ((elem-hash (comparator-hash-function element-comparator))
  282. (acc (make-hasher))
  283. (len (length obj)))
  284. (let loop ((n 0))
  285. (cond
  286. ((= n len) (acc))
  287. (else (acc (elem-hash (ref obj n))) (loop (+ n 1))))))))
  288. (define (string-hash obj)
  289. (let ((acc (make-hasher))
  290. (len (string-length obj)))
  291. (let loop ((n 0))
  292. (cond
  293. ((= n len) (acc))
  294. (else (acc (char->integer (string-ref obj n))) (loop (+ n 1)))))))