Newer
Older
;;; -*- Mode: Lisp ; Base: 10 ; Syntax: ANSI-Common-Lisp -*-
;;;;; Order
#+xcvb
(module
(:depends-on
("package"
"base/strings"
"base/symbols"
"interface/interface"
"interface/eq")))
(defpackage :order
(:use :interface :eq :cl :fare-utils)
(:export
Francois-Rene Rideau
committed
#:<order> #:<number> #:<string> #:<char>
#:<order-from-lessp> #:<lessp>
#:<order-from-compare> #:<compare>
#:<key> #:<order-parameter>
#:order< #:order<= #:order> #:order>= #:== #:compare
(define-interface <order> (<eq>) ())
(defgeneric order< (i x y))
(defgeneric order<= (i x y))
(defgeneric order> (i x y))
(defgeneric order>= (i x y))
(defgeneric compare (i x y))
(define-interface <order-from-lessp> (<order>) ())
(defmethod order<= ((i <order-from-lessp>) x y)
(not (order< i y x)))
(defmethod order> ((i <order-from-lessp>) x y)
(order< i y x))
(defmethod order>= ((i <order-from-lessp>) x y)
(not (order< i x y)))
(defmethod == ((i <order-from-lessp>) x y)
(not (or (order< i x y) (order< i y x))))
(defmethod compare ((i <order-from-lessp>) x y)
(cond
((order< i x y) -1)
((order> i x y) 1)
(t 0)))
(define-interface <order-from-compare> (<order>) ())
(defmethod order< ((i <order-from-compare>) x y)
(ecase (compare i x y)
((-1) t)
((0 1) nil)))
(defmethod order<= ((i <order-from-compare>) x y)
(ecase (compare i x y)
((-1 0) t)
(1 nil)))
(defmethod order> ((i <order-from-compare>) x y)
(ecase (compare i x y)
((-1 0) nil)
((1) t)))
(defmethod order>= ((i <order-from-compare>) x y)
(ecase (compare i x y)
((-1) nil)
((0 1) t)))
(defmethod == ((i <order-from-compare>) x y)
(ecase (compare i x y)
((-1 1) nil)
((0) t)))
(define-interface <compare> (<order-from-compare>)
((compare :initarg :compare :reader compare-function))
(:parametric (compare) (make-interface :compare compare)))
(defmethod compare ((i <compare>) x y)
(funcall (compare-function i) x y))
(define-interface <lessp> (<order-from-lessp>)
((lessp :initarg :lessp :reader lessp-function))
(:parametric (lessp) (make-interface :lessp lessp)))
Francois-Rene Rideau
committed
(macrolet ((delegate (&rest names)
`(progn
,@(loop :for (name suffix) :in names :collect
`(defmethod ,name ((i <lessp>) x y)
(,(conc-symbol :call suffix) (lessp-function i)
Francois-Rene Rideau
committed
(funcall (key-function i) x)
(funcall (key-function i) y)))))))
(delegate (order< <) (order<= <=) (order> >) (order>= >=)
(== =) (compare -compare)))
Francois-Rene Rideau
committed
(defun call< (lessp x y)
(funcall lessp x y))
Francois-Rene Rideau
committed
(not (funcall lessp y x)))
Francois-Rene Rideau
committed
(funcall lessp y x))
Francois-Rene Rideau
committed
(not (funcall lessp x y)))
Francois-Rene Rideau
committed
(not (or (funcall lessp x y) (funcall lessp y x))))
Francois-Rene Rideau
committed
(cond
((funcall lessp x y) -1)
((funcall lessp y x) 1)
Francois-Rene Rideau
committed
(t 0)))
(macrolet ((builtin (name prefix)
`(progn
(define-interface ,name (<order>) () (:singleton))
Francois-Rene Rideau
committed
,@(loop :for n :in '(< <= > >=) :collect
`(defmethod ,(conc-symbol :order n) ((i ,name) x y)
Francois-Rene Rideau
committed
(,(conc-symbol prefix n) x y)))
(defmethod == ((i ,name) x y)
(,(conc-symbol prefix '=) x y))
(defmethod compare ((i ,name) x y)
Francois-Rene Rideau
committed
(cond
((,(conc-symbol prefix '<) x y) -1)
((,(conc-symbol prefix '>) x y) 1)
Francois-Rene Rideau
committed
;;(builtin function call)
Francois-Rene Rideau
committed
(builtin <number> "")
(builtin <char> char)
(builtin <string> string))
Francois-Rene Rideau
committed
(define-interface <key> ()
Francois-Rene Rideau
committed
((order-key :initarg :key :reader key-function)
(order-key-interface :initarg :order :reader order-interface))
(:parametric (&key key order) (make-interface :key key :order order)))
Francois-Rene Rideau
committed
(macrolet ((delegate (&rest names)
`(progn
,@(loop :for name :in names :collect
Francois-Rene Rideau
committed
(,name (order-interface i)
(funcall (key-function i) x)
(funcall (key-function i) y)))))))
(delegate order< order<= order> order>= == compare))
Francois-Rene Rideau
committed
(define-interface <order-parameter> ()
Francois-Rene Rideau
committed
((order-interface :initarg :order :reader order-interface)))
(macrolet ((delegate (&rest names)
`(progn
,@(loop :for name :in names :collect
`(defmethod ,name ((i <order-parameter>) x y)
Francois-Rene Rideau
committed
(,name (order-interface i) x y))))))
(delegate order< order<= order> order>= == compare))
Francois-Rene Rideau
committed
;;; simple algorithm using order
Francois-Rene Rideau
committed
(defun sorted-list-differences (list1 list2 &key (order <number>))
Francois-Rene Rideau
committed
(labels
((rec (list1 list2 only1 common only2)
(cond
((and (null list1) (null list2))
(values (nreverse only1) (nreverse common) (nreverse only2)))
((null list1)
(values (nreverse only1) (nreverse common) (nreconc only2 list2)))
((null list2)
(values (nreconc only1 list1) (nreverse common) (nreverse only2)))
(t
(let ((r (compare order (car list1) (car list2))))
(cond
((= r 0)
(rec (cdr list1) (cdr list2) only1 (cons (car list1) common) only2))
((< r 0)
(rec (cdr list1) list2 (cons (car list1) only1) common only2))
(t ;(> r 0)
(rec list1 (cdr list2) only1 common (cons (car list2) only2)))))))))
(rec list1 list2 nil nil nil)))