#lang racket/base (require racket/dict racket/contract/base racket/string unstable/prop-contract) (define ordering/c (or/c '= '< '>)) (provide ordering/c) (define-values (prop:ordered-dict ordered-dict? ordered-dict-ref) (make-struct-type-property 'ordered-dict #f)) (define extreme-contract (->i ([d ordered-dict?]) [_r (d) (or/c #f (dict-iter-contract d))])) (define search-contract (->i ([d ordered-dict?] [k (d) (dict-key-contract d)]) [_r (d) (or/c #f (dict-iter-contract d))])) (define prop:ordered-dict-contract (let ([e extreme-contract] [s search-contract]) (vector-immutable/c e ;; iterate-least e ;; iterate-greatest s ;; iterate-least/>? s ;; iterate-least/>=? s ;; iterate-greatest/? d k) (appd d 2 k)) (define (dict-iterate-least/>=? d k) (appd d 3 k)) (define (dict-iterate-greatest/ any/c boolean?)] [dict-iterate-least extreme-contract] [dict-iterate-greatest extreme-contract] [dict-iterate-least/>? search-contract] [dict-iterate-least/>=? search-contract] [dict-iterate-greatest/] [else (incomparable name x y)])) = <)] [(name ctc = < >) (order name ctc (lambda (x y) (cond [(= x y) '=] [(< x y) '<] [(> x y) '>] [else (incomparable name x y)])) = <)])]) order)) (define (incomparable name x y) (error name "values are incomparable: ~e ~e" x y)) (provide/contract [rename order* order (->* (symbol? contract? procedure?) (procedure? procedure?) order?)] [order? (-> any/c boolean?)] [order-comparator (-> order? procedure?)] [order- order? procedure?)] [order-=? (-> order? procedure?)] [order-domain-contract (-> order? contract?)]) ;; ============================================================ (define (real/not-NaN? x) (and (real? x) (not (eqv? x +nan.0)))) (define real-order (order* 'real-order real/not-NaN? = < >)) (provide/contract [real-order order?]) ;; ============================================================ #| natural-cmp : Comparator datum-cmp : Comparator comparators for (most) built-in values !! May diverge on cyclical input. natural-cmp: * restriction to reals equiv to <,= real (exact and inexact, #e1 = #i1, +nan.0 not allowed!) < complex < Other datum-cmp: * restriction to reals NOT EQUIV to <,= (separates exact, inexact) exact real < inexact real (+nan.0 > +inf.0) < complex < Other Other: string < bytes < keyword < symbol < bool < char < null < pair < vector < box < prefab ;; FIXME: What else to add? regexps (4 kinds?), syntax, ... |# ;; not exported because I'm not sure it's a good idea and I'm not sure ;; how to characterize it (define (natural-cmp x y) (gen-cmp x y #t)) (define (datum-cmp x y) (gen-cmp x y #f)) (define (gen-cmp x y natural?) (define-syntax-rule (recur x* y*) (gen-cmp x* y* natural?)) #| (cond ... [(T? x) ...] ;; at this point, Type(x) > T [(T? y) ;; Type(x) > T = Type(y), so: '>]) Assumes arguments are legal. |# (cond [(real? x) (if (real? y) (cond [natural? (cmp* < = x y)] [else ;; exact < inexact (cond [(and (exact? x) (exact? y)) (cmp* < = x y)] [(exact? x) ;; inexact y '<] [(exact? y) ;; inexact x '>] [(and (eqv? x +nan.0) (eqv? y +nan.0)) '=] [(eqv? x +nan.0) '>] [(eqv? y +nan.0) '<] [else ;; inexact x, inexact y (cmp* < = x y)])]) '<)] [(real? y) '>] [(complex? x) (if (complex? y) (lexico (recur (real-part x) (real-part y)) (recur (imag-part x) (imag-part y))) '<)] [(complex? y) '>] [(string? x) (if (string? y) (cmp* string] [(bytes? x) (if (bytes? y) (cmp* bytes] [(keyword? x) (if (keyword? y) (cmp* keyword] [(symbol? x) (if (symbol? y) (cmp* symbol] [(boolean? x) (if (boolean? y) (cond [(eq? x y) '=] [y '<] [else '>]) '<)] [(boolean? y) '>] [(char? x) (if (char? y) (cmp* char] [(null? x) (if (null? y) '= '<)] [(null? y) '>] [(pair? x) (if (pair? y) (lexico (recur (car x) (car y)) (recur (cdr x) (cdr y))) '<)] [(pair? y) '>] [(vector? x) (if (vector? y) (vector] [(box? x) (if (box? y) (recur (unbox x) (unbox y)) '<)] [(box? y) '>] [(prefab-struct-key x) (if (prefab-struct-key y) (lexico (recur (prefab-struct-key x) (prefab-struct-key y)) (vectorvector x) (struct->vector y) 1 natural?)) '<)] [(prefab-struct-key y) '>] [else (raise-type-error (if natural? 'natural-cmp 'datum-cmp) (string-join '("number" "string" "bytes" "keyword" "symbol" "boolean" "character" "null" "pair" "vector" "box" "or prefab struct") ", ") 0 x y)])) (define-syntax-rule (cmp* )))) (define-syntax-rule (lexico c1 c2) (case c1 ((<) '<) ((=) c2) ((>) '>))) (define (symbolstring x) (symbol->string y))) (define (vector)] [(< i (vector-length y)) '<] [else '=])) (define datum-order (order* 'datum-order any/c datum-cmp)) (provide/contract [datum-order order?])