1.10 Comparators
(require rebellion/base/comparator) | package: rebellion |
A comparator is an object that compares two values and determines whether one is greater than the other, or whether they are equivalent. This comparison must respect some total ordering, meaning that for any two values x and y:
If x is less than y, then y must be greater than x. The reverse must hold true if x is greater than y.
If x is equivalent to y, then y must be equivalent to x.
If x is equal? to y, they must be equivalent.
Note that the third requirement above does not imply that all equivalent values must be equal?. For example, the real<=> comparator considers 3 and 3.0 equivalent, but (equal? 3 3.0) returns false. A comparator for which all equivalent values are also equal is said to be consistent with equality, and comparators which do not satisfy this stronger property are inconsistent with equality. All comparators defined in rebellion/base/comparator are consistent with equality unless otherwise stated.
procedure
(comparator? v) → boolean?
v : any/c
procedure
(compare comparator left right) → comparison?
comparator : comparator? left : any/c right : any/c
1.10.1 Constructing Comparators
procedure
(comparator-map comparator f [#:name name]) → comparator?
comparator : comparator? f : (-> any/c any/c) name : (or/c interned-symbol? #f) = #f
> (define-record-type circle (color radius)) > (define circle<=> (comparator-map real<=> circle-radius))
> (compare circle<=> (circle #:color 'green #:radius 5) (circle #:color 'blue #:radius 8)) #<lesser>
procedure
(make-comparator function [#:name name]) → comparator?
function : (-> any/c any/c comparison?) name : (or/c interned-symbol? #f) = #f
(define symbol<=> (make-comparator (λ (left right) (cond [(symbol<? left right) lesser] [(equal? left right) equivalent] [else greater])) #:name 'symbol<=>))
> (compare symbol<=> 'apple 'banana) #<lesser>
> (compare symbol<=> 'apple 'aardvark) #<greater>
procedure
(comparator-reverse comparator) → comparator?
comparator : comparator?
> (compare real<=> 2 5) #<lesser>
> (compare (comparator-reverse real<=>) 2 5) #<greater>
1.10.2 Predefined Comparators
value
> (compare real<=> 42 99.99) #<lesser>
> (compare real<=> 42 +inf.0) #<lesser>
> (compare real<=> 42 -inf.0) #<greater>
> (compare real<=> 42 +nan.0) real<=>: contract violation
expected: comparable-real?
given: +nan.0
in: an operand of
(comparator/c comparable-real?)
contract from:
<pkgs>/rebellion/private/comparator.rkt
blaming: top-level
(assuming the contract is correct)
at: <pkgs>/rebellion/private/comparator.rkt:23.3
Beware that this comparator is inconsistent with equality, as it ignores the exactness of the compared numbers. This is the same behavior as <, =, and >, but it means that two un-equal? numbers may compare equivalent.
> (compare real<=> 5 5.0) #<equivalent>
> (compare real<=> -0.0 0.0) #<equivalent>
> (compare real<=> +inf.0 +inf.0) #<equivalent>
procedure
(comparable-real? v) → boolean?
v : any/c
> (comparable-real? 42) #t
> (comparable-real? +inf.0) #t
> (comparable-real? +nan.0) #f
value
> (compare string<=> "aardvark" "zebra") #<lesser>
> (compare string<=> "aardvark" (make-string 5 #\z)) string<=>: contract violation
expected: immutable-string?
given: "zzzzz"
in: an operand of
(comparator/c immutable-string?)
contract from:
<pkgs>/rebellion/private/comparator.rkt
blaming: top-level
(assuming the contract is correct)
at: <pkgs>/rebellion/private/comparator.rkt:24.3
1.10.3 Comparison Constants
procedure
(comparison? v) → boolean?
v : any/c
value
value
value
1.10.4 Comparator Contracts
procedure
(comparator/c operand-contract) → contract?
operand-contract : contract?
(define/contract even-integer<=> (comparator/c (and/c integer? even?)) real<=>)
> (compare even-integer<=> 2 8) #<lesser>
> (compare even-integer<=> 3 8) even-integer<=>: contract violation
expected: even?
given: 3
in: an and/c case of
an operand of
(comparator/c (and/c integer? even?))
contract from: (definition even-integer<=>)
blaming: top-level
(assuming the contract is correct)
at: eval:2.0
1.10.5 Comparator Chaperones and Impersonators
procedure
(comparator-impersonate comparator [ #:operand-guard operand-guard #:properties properties #:comparison-marks marks #:chaperone? chaperone?]) → comparator? comparator : comparator? operand-guard : (or/c (-> any/c any/c #f)) = #f
properties : (hash/c impersonator-property? any/c #:immutable #t) = empty-hash marks : immutable-hash? = empty-hash chaperone? : boolean? = (false? operand-guard)
If chaperone? is true, the returned impersonator is a chaperone. In that case, operand-guard must always return a value equal to the one it is given. Furthermore, any impersonators returned from operand-guard must be chaperones.
(define printing-real<=> (comparator-impersonate real<=> #:operand-guard (λ (x) (printf "Got ~a\n" x) x) #:chaperone? #t))
> (compare printing-real<=> 4 8)
Got 4
Got 8
#<lesser>
> (chaperone-of? printing-real<=> real<=>) #t