((section 2 "Outdated egg!" (p "This is an egg for CHICKEN 4, the unsupported old release.  You're almost certainly looking for " (int-link "/eggref/5/genequal" "the CHICKEN 5 version of this egg") ", if it exists.") (p "If it does not exist, there may be equivalent functionality provided by another egg; have a look at the " (link "https://wiki.call-cc.org/chicken-projects/egg-index-5.html" "egg index") ". Otherwise, please consider porting this egg to the current version of CHICKEN.")) (section 2 "genequal" (toc) (section 3 "Description" (p "Compares " (i "obj1") " and " (i "obj2") " for equality using user-specified and built-in comparators.")) (section 3 "Author" (p (int-link "/users/john-cowan" "John Cowan"))) (section 3 "Requirements" (p "None")) (section 3 ("Generalized " (tt "equal?") " predicate") (def (sig (procedure "(generalized-equal? obj1 obj2 . comparator-list)" (id generalized-equal?))) (p "A " (i "comparator") " is a procedure that is given two arguments to compare.  It returns " (tt "#t") " if its arguments are to be considered equal, " (tt "#f") " if they are to be considered unequal, and any other value if it cannot decide.  The third argument passed to a comparator is a list of comparators to be used in recursive calls to " (tt "generalized-equal?") ".") (p "First, each element of " (i "comparator-list") "  is invoked on " (i "obj1") " and " (i "obj2") ", passing " (i "comparator-list") " as its third argument.  If the comparator returns " (tt "#t") " or " (tt "#f") ", that is the result.") (p "If all comparators in the list have been invoked without a " (tt "#t") " or " (tt "#f") " result, then " (tt "generalized-equal?") " determines if both " (i "obj1") " and " (i "obj2") " are pairs, strings, vectors, u8vectors, hash tables with the same test function, or SRFI-99 records of the same type.  (It cannot introspect on SRFI-9 or Chicken-native records.)  If they are not, then " (tt "generalized-equal?") " returns what " (tt "eqv?") " returns on " (i "obj1") " and " (i "obj2") ".") (p "Otherwise, if the containers have different numbers of elements, the result is " (tt "#f") ".  Otherwise, " (tt "generalized-equal?") " invokes itself recursively on each corresponding element of the containers, passing itself the same comparators.  If a recursive call returns " (tt "#f") ", that is the result; if all recursive calls return " (tt "#t") ", that is the result.")) (def (sig (procedure "(predicates->comparator  type-predicate compare-predicate)" (id predicates->comparator))) (p "Returns a comparator that invokes " (i "type-predicate") " on its first and its second arguments.  If they both return " (tt "#t") ", then they are assumed to be of the same type, and " (i "compare-predicate") " is invoked on the first and second arguments together.  If the result is " (tt "#t") " or " (tt "#f") ", then the comparator returns " (tt "#t") " or " (tt "#f") " respectively.  If they are not of the same type, a third value is returned.  The comparator always ignores its third argument."))) (section 3 "Comparators" (p "Specifying all three of these comparators causes " (tt "generalized-equal?") " to act like Common Lisp's " (tt "EQUALP") ".") (def (sig (procedure "(numeric-comparator  obj1 obj2 comparators-list)" (id numeric-comparator))) (p "A comparator that returns " (tt "#t") " if " (i "obj1") " and " (i "obj2") " are numbers that are equal by " (tt "=") ", " (tt "#f") " if they are not equal by " (tt "=") ", and a third value otherwise.  The " (i "comparators-list") " argument is ignored.")) (def (sig (procedure "(char-ci-comparator  obj1 obj2 comparators-list)" (id char-ci-comparator))) (p "A comparator that returns " (tt "#t") " if " (i "obj1") " and " (i "obj2") " are both characters that are equal by " (tt "char-ci=?") ", " (tt "#f") " if they are not equal by " (tt "char-ci=?") ", and a third value otherwise.  The " (i "comparators-list") " argument is ignored.")) (def (sig (procedure "(string-ci-comparator  obj1 obj2 comparators-list)" (id string-ci-comparator))) (p "A comparator that returns " (tt "#t") " if " (i "obj1") " and " (i "obj2") " are both strings that are equal by " (tt "string-ci=?") ", " (tt "#f") " if they are not equal by " (tt "string-ci=?") ", and a third value otherwise.  The " (i "comparators-list") " argument is ignored."))) (section 3 "Examples" (highlight scheme "(use genequal)\n\n(use srfi-99)\n(define-record-type foo (make-foo x) foo? (x foo-x foo-set-x!))\n(define-record-type bar (make-bar x) bar? (x bar-x))\n(define a (make-foo 10))\n(define b (make-foo 10))\n(define c (make-bar 10))\n\n(generalized-equal? a b) => #t\n(generalized-equal? a c) => #f\n(foo-set-x! a 20)\n(generalized-equal? a b) => #f\n\n(generalized-equal? '(\"A\" \"B\") '(\"a\" \"b\")) => #f\n\n(generalized-equal? '(\"A\" \"B\") '(\"a\" \"b\") string-ci-comparator) => #t\n\n(generalized-equal? 2 2.0) => #f\n(generalized-equal? 2 2.0 numeric-comparator) => #t\n")) (section 3 "License" (p "BSD")) (section 3 "Version history" (section 4 "Version 0.1" (p "Initial release")))))