From a9897295de1c5b7da066aa2693e9dbfeff282fc2 Mon Sep 17 00:00:00 2001 From: Leah Neukirchen Date: Mon, 2 Jan 2023 21:14:34 +0100 Subject: add generic comparison --- mew.scm | 54 ++++++++++++++++++++++++++++++++++++++++++++++++- mew.svnwiki | 26 ++++++++++++++++++++++++ tests/test.mew | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 142 insertions(+), 1 deletion(-) diff --git a/mew.scm b/mew.scm index 7de52f0..1f25c79 100644 --- a/mew.scm +++ b/mew.scm @@ -2,7 +2,7 @@ (export act accumulate andloc app at boolean - comp cross-product + cmp comp cross-product dec dec! def del-at div dup empty? eof esc fail fin final for for/into fun* @@ -27,6 +27,7 @@ xcond xfold xfold-right xreduce xreduce-right xscan xscan-right -> fun-> fun->> set-> =? <>? + ? >=? ~? => =>* and=> fun=> op=> set=> @@ -1295,6 +1296,57 @@ ((char? o) (make-string n o)) (#t (error "no repeat defined")))) + (define (cmp a b) + (cond ((and (real? a) (real? b) (= a b)) 0) + ((and (real? a) (real? b) (< a b)) -1) + ((and (real? a) (real? b) (> a b)) 1) + + ((and (char? a) (char? b) (char=? a b)) 0) + ((and (char? a) (char? b) (char? a b)) 1) + + ((and (string? a) (string? b) (string=? a b)) 0) + ((and (string? a) (string? b) (string? a b)) 1) + + ((and (null? a) (null? b)) 0) + ((and (list? a) (null? b)) 1) + ((and (null? a) (list? b)) -1) + ((and (list? a) (list? b)) (let ((c (cmp (car a) (car b)))) + (if (zero? c) + (cmp (cdr a) (cdr b)) + c))) + + ((and (vector? a) (vector? b)) (let ((m (min (vector-length a) + (vector-length b)))) + (let loop ((i 0)) + (if (< i m) + (let ((c (cmp (vector-ref a i) + (vector-ref b i)))) + (if (zero? c) + (loop (+ i 1)) + c)) + (cmp (vector-length a) + (vector-length b)))))) + + (else #f))) + + (define (cmp-op f) + (case-lambda + ((a b) (f (cmp a b))) + ((a b . xs) + (let loop ((x a) (xs (cons b xs))) + (if (null? xs) + #t + (if (f (cmp x (car xs))) + (loop (car xs) (cdr xs)) + #f)))))) + + (define ? (cmp-op positive?)) + (define >=? (cmp-op (negate negative?))) + (let ((old-repl-prompt (repl-prompt))) (repl-prompt (lambda () (let ((old-prompt (old-repl-prompt))) diff --git a/mew.svnwiki b/mew.svnwiki index dce8f34..ffb99cb 100644 --- a/mew.svnwiki +++ b/mew.svnwiki @@ -355,6 +355,32 @@ set of keys and {{equal?}} values. Return true if all values are pairwise different. +== Generic comparison + +(cmp ) + +Compare the real/char/string/list/vector {{}} to {{}} and +return -1 if {{}} is less than {{}}, +0 if {{}} is equal to {{}} +1 if {{}} is greater than {{}}. +Return false if {{}} and {{}} cannot be compared. + +Lists and vectors are compared in lexicographic order using {{cmp}} +recursively. + +( ...) +(>? ...) +(<=? ...) +(>=? ...) + +Return true if all arguments are monotonically increasing, +monotonically decreasing, monotonically non-decreasing, or +monotonically non-increasing according to {{cmp}}, and false +otherwise. + +It is an error to compare uncomparable values. + + == Data types (get ) diff --git a/tests/test.mew b/tests/test.mew index 96f0764..246f9e7 100644 --- a/tests/test.mew +++ b/tests/test.mew @@ -729,3 +729,66 @@ (test #() (repeat #(1 2 3) 0)) (test "" (repeat "123" 0)) (test "" (repeat #\x 0))) + +(test-group "cmp" + (test -1 (cmp 4 5)) + (test -1 (cmp -4 5)) + (test -1 (cmp -5 -4)) + (test -1 (cmp 4 5.5)) + (test 0 (cmp 4 4.0)) + (test 0 (cmp -0.0 0.0)) + (test 1 (cmp 1/4 1/5)) + (test 1 (cmp 5 4)) + + (test -1 (cmp "bar" "foo")) + (test 1 (cmp "foo" "bar")) + (test 0 (cmp "foo" "foo")) + (test -1 (cmp "foo" "foox")) + (test -1 (cmp "fo" "foo")) + + (test -1 (cmp #\a #\z)) + (test 0 (cmp #\a #\a)) + (test 1 (cmp #\z #\a)) + + (test -1 (cmp '(1 2 3) '(1 2 4))) + (test 0 (cmp '(1 2 3) '(1 2 3))) + (test 1 (cmp '(1 2 5) '(1 2 3))) + (test 1 (cmp '(1 2 3) '(1 2))) + + (test -1 (cmp #(1 2 3) #(1 2 4))) + (test 0 (cmp #(1 2 3) #(1 2 3))) + (test 1 (cmp #(1 2 5) #(1 2 3))) + (test 1 (cmp #(1 2 3) #(1 2))) + + (test #f (cmp 42 "foo"))) + +(test-group "?" + (test #f (>? 1 2 3)) + (test #t (>? 3 2 1)) + (test #f (>? 1 1 2)) + + (test-error (>? "foo" 2 #(6 7 8)))) + +(test-group ">=?" + (test #f (>=? 1 2 3)) + (test #t (>=? 3 2 1)) + (test #t (>=? 2 1 1)) + + (test-error (>=? "foo" 2 #(6 7 8)))) -- cgit 1.4.1