diff options
author | Stuart Sierra <mail@stuartsierra.com> | 2010-08-07 16:41:53 -0400 |
---|---|---|
committer | Stuart Sierra <mail@stuartsierra.com> | 2010-08-07 16:41:53 -0400 |
commit | a6a92b9b3d2bfd9a56e1e5e9cfba706d1aeeaae5 (patch) | |
tree | f1f3da9887dc2dc557df3282b0bcbd4d701ec593 /modules/generic/src | |
parent | e7930c85290f77815cdb00a60604feedfa2d0194 (diff) |
Split all namespaces into sub-modules.
* Examples and tests have not been copied over.
* Clojure test/compile phases are commented out in parent POM.
* May require installing parent POM before full build.
Diffstat (limited to 'modules/generic/src')
6 files changed, 739 insertions, 0 deletions
diff --git a/modules/generic/src/main/clojure/clojure/contrib/generic.clj b/modules/generic/src/main/clojure/clojure/contrib/generic.clj new file mode 100644 index 00000000..44cc6db7 --- /dev/null +++ b/modules/generic/src/main/clojure/clojure/contrib/generic.clj @@ -0,0 +1,54 @@ +;; Support code for generic interfaces + +;; by Konrad Hinsen +;; last updated May 4, 2009 + +;; Copyright (c) Konrad Hinsen, 2009. All rights reserved. The use +;; and distribution terms for this software are covered by the Eclipse +;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) +;; which can be found in the file epl-v10.html at the root of this +;; distribution. By using this software in any fashion, you are +;; agreeing to be bound by the terms of this license. You must not +;; remove this notice, or any other, from this software. + +(ns + ^{:author "Konrad Hinsen" + :skip-wiki true + :doc "Generic interfaces + This library provides generic interfaces in the form of + multimethods that can be implemented for any type. + The interfaces partly duplicate existing non-generic + functions in clojure.core (arithmetic, comparison, + collections) and partly provide additional functions that + can be defined for a wide variety of types (functors, math + functions). More functions will be added in the future."} + clojure.contrib.generic + (:use [clojure.contrib.types :only (defadt)])) + +; +; A dispatch function that separates nulary, unary, binary, and +; higher arity calls and also selects on type for unary and binary +; calls. +; +(defn nary-dispatch + ([] ::nulary) + ([x] (type x)) + ([x y] + [(type x) (type y)]) + ([x y & more] ::nary)) + +; +; We can't use [::binary :default], so we need to define a root type +; of the type hierarcy. The derivation for Object covers all classes, +; but all non-class types will need an explicit derive clause. +; Ultimately, a macro might take care of this. +; +(def root-type ::any) +(derive Object root-type) + +; +; Symbols referring to ::nulary and ::n-ary +; +(def nulary-type ::nulary) +(def nary-type ::nary) + diff --git a/modules/generic/src/main/clojure/clojure/contrib/generic/arithmetic.clj b/modules/generic/src/main/clojure/clojure/contrib/generic/arithmetic.clj new file mode 100644 index 00000000..04f2c318 --- /dev/null +++ b/modules/generic/src/main/clojure/clojure/contrib/generic/arithmetic.clj @@ -0,0 +1,201 @@ +;; Generic interfaces for arithmetic operations + +;; by Konrad Hinsen +;; last updated May 5, 2009 + +;; Copyright (c) Konrad Hinsen, 2009. All rights reserved. The use +;; and distribution terms for this software are covered by the Eclipse +;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) +;; which can be found in the file epl-v10.html at the root of this +;; distribution. By using this software in any fashion, you are +;; agreeing to be bound by the terms of this license. You must not +;; remove this notice, or any other, from this software. + +(ns + ^{:author "Konrad Hinsen" + :doc "Generic arithmetic interface + This library defines generic versions of + - * / as multimethods + that can be defined for any type. The minimal required + implementations for a type are binary + and * plus unary - and /. + Everything else is derived from these automatically. Explicit + binary definitions for - and / can be provided for + efficiency reasons."} + clojure.contrib.generic.arithmetic + (:use [clojure.contrib.generic + :only (root-type nulary-type nary-type nary-dispatch)] + [clojure.contrib.types :only (defadt)]) + (:refer-clojure :exclude [+ - * /])) + +; +; Universal zero and one values +; +(defadt ::zero zero) +(defadt ::one one) + +(derive ::zero root-type) +(derive ::one root-type) + +; +; Addition +; +; The minimal implementation is for binary my-type. It is possible +; in principle to implement [::unary my-type] as well, though this +; doesn't make any sense. +; +(defmulti + + "Return the sum of all arguments. The minimal implementation for type + ::my-type is the binary form with dispatch value [::my-type ::my-type]." + {:arglists '([x] [x y] [x y & more])} + nary-dispatch) + +(defmethod + nulary-type + [] + zero) + +(defmethod + root-type + [x] x) + +(defmethod + [root-type ::zero] + [x y] x) + +(defmethod + [::zero root-type] + [x y] y) + +(defmethod + nary-type + [x y & more] + (if more + (recur (+ x y) (first more) (next more)) + (+ x y))) + +; +; Subtraction +; +; The minimal implementation is for unary my-type. A default binary +; implementation is provided as (+ x (- y)), but it is possible to +; implement unary my-type explicitly for efficiency reasons. +; +(defmulti - + "Return the difference of the first argument and the sum of all other + arguments. The minimal implementation for type ::my-type is the binary + form with dispatch value [::my-type ::my-type]." + {:arglists '([x] [x y] [x y & more])} + nary-dispatch) + +(defmethod - nulary-type + [] + (throw (java.lang.IllegalArgumentException. + "Wrong number of arguments passed"))) + +(defmethod - [root-type ::zero] + [x y] x) + +(defmethod - [::zero root-type] + [x y] (- y)) + +(defmethod - [root-type root-type] + [x y] (+ x (- y))) + +(defmethod - nary-type + [x y & more] + (if more + (recur (- x y) (first more) (next more)) + (- x y))) + +; +; Multiplication +; +; The minimal implementation is for binary [my-type my-type]. It is possible +; in principle to implement unary my-type as well, though this +; doesn't make any sense. +; +(defmulti * + "Return the product of all arguments. The minimal implementation for type + ::my-type is the binary form with dispatch value [::my-type ::my-type]." + {:arglists '([x] [x y] [x y & more])} + nary-dispatch) + +(defmethod * nulary-type + [] + one) + +(defmethod * root-type + [x] x) + +(defmethod * [root-type ::one] + [x y] x) + +(defmethod * [::one root-type] + [x y] y) + +(defmethod * nary-type + [x y & more] + (if more + (recur (* x y) (first more) (next more)) + (* x y))) + +; +; Division +; +; The minimal implementation is for unary my-type. A default binary +; implementation is provided as (* x (/ y)), but it is possible to +; implement binary [my-type my-type] explicitly for efficiency reasons. +; +(defmulti / + "Return the quotient of the first argument and the product of all other + arguments. The minimal implementation for type ::my-type is the binary + form with dispatch value [::my-type ::my-type]." + {:arglists '([x] [x y] [x y & more])} + nary-dispatch) + +(defmethod / nulary-type + [] + (throw (java.lang.IllegalArgumentException. + "Wrong number of arguments passed"))) + +(defmethod / [root-type ::one] + [x y] x) + +(defmethod / [::one root-type] + [x y] (/ y)) + +(defmethod / [root-type root-type] + [x y] (* x (/ y))) + +(defmethod / nary-type + [x y & more] + (if more + (recur (/ x y) (first more) (next more)) + (/ x y))) + +; +; Macros to permit access to the / multimethod via namespace qualification +; +(defmacro defmethod* + "Define a method implementation for the multimethod name in namespace ns. + Required for implementing the division function from another namespace." + [ns name & args] + (let [qsym (symbol (str ns) (str name))] + `(defmethod ~qsym ~@args))) + +(defmacro qsym + "Create the qualified symbol corresponding to sym in namespace ns. + Required to access the division function from another namespace, + e.g. as (qsym clojure.contrib.generic.arithmetic /)." + [ns sym] + (symbol (str ns) (str sym))) + +; +; Minimal implementations for java.lang.Number +; +(defmethod + [java.lang.Number java.lang.Number] + [x y] (clojure.core/+ x y)) + +(defmethod - java.lang.Number + [x] (clojure.core/- x)) + +(defmethod * [java.lang.Number java.lang.Number] + [x y] (clojure.core/* x y)) + +(defmethod / java.lang.Number + [x] (clojure.core// x)) + diff --git a/modules/generic/src/main/clojure/clojure/contrib/generic/collection.clj b/modules/generic/src/main/clojure/clojure/contrib/generic/collection.clj new file mode 100644 index 00000000..cdca97fb --- /dev/null +++ b/modules/generic/src/main/clojure/clojure/contrib/generic/collection.clj @@ -0,0 +1,116 @@ +;; Generic interfaces for collection-related functions + +;; by Konrad Hinsen +;; last updated May 5, 2009 + +;; Copyright (c) Konrad Hinsen, 2009. All rights reserved. The use +;; and distribution terms for this software are covered by the Eclipse +;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) +;; which can be found in the file epl-v10.html at the root of this +;; distribution. By using this software in any fashion, you are +;; agreeing to be bound by the terms of this license. You must not +;; remove this notice, or any other, from this software. + +(ns + ^{:author "Konrad Hinsen" + :doc "Generic arithmetic interface + This library defines generic versions of common + collection-related functions as multimethods that can be + defined for any type."} + clojure.contrib.generic.collection + (:refer-clojure :exclude [assoc conj dissoc empty get into seq])) + +; +; assoc +; +(defmulti assoc + "Returns a new collection in which the values corresponding to the + given keys are updated by the given values. Each type of collection + can have specific restrictions on the possible keys." + {:arglists '([coll & key-val-pairs])} + (fn [coll & items] (type coll))) + +(defmethod assoc :default + [map & key-val-pairs] + (apply clojure.core/assoc map key-val-pairs)) + +; assoc-in + +; +; conj +; +(defmulti conj + "Returns a new collection resulting from adding all xs to coll." + {:arglists '([coll & xs])} + (fn [coll & xs] (type coll))) + +(defmethod conj :default + [coll & xs] + (apply clojure.core/conj coll xs)) + +; +; diassoc +; +(defmulti dissoc + "Returns a new collection in which the entries corresponding to the + given keys are removed. Each type of collection can have specific + restrictions on the possible keys." + {:arglists '([coll & keys])} + (fn [coll & keys] (type coll))) + +(defmethod dissoc :default + [map & keys] + (apply clojure.core/dissoc map keys)) + +; +; empty +; +(defmulti empty + "Returns an empty collection of the same kind as the argument" + {:arglists '([coll])} + type) + +(defmethod empty :default + [coll] + (clojure.core/empty coll)) + +; +; get +; +(defmulti get + "Returns the element of coll referred to by key. Each type of collection + can have specific restrictions on the possible keys." + {:arglists '([coll key] [coll key not-found])} + (fn [coll & args] (type coll))) + +(defmethod get :default + ([coll key] + (clojure.core/get coll key)) + ([coll key not-found] + (clojure.core/get coll key not-found))) + +; +; into +; +(defmulti into + "Returns a new coll consisting of to-coll with all of the items of + from-coll conjoined." + {:arglists '([to from])} + (fn [to from] (type to))) + +(declare seq) +(defmethod into :default + [to from] + (reduce conj to (seq from))) + +; +; seq +; +(defmulti seq + "Returns a seq on the object s." + {:arglists '([s])} + type) + +(defmethod seq :default + [s] + (clojure.core/seq s)) diff --git a/modules/generic/src/main/clojure/clojure/contrib/generic/comparison.clj b/modules/generic/src/main/clojure/clojure/contrib/generic/comparison.clj new file mode 100644 index 00000000..e41b0792 --- /dev/null +++ b/modules/generic/src/main/clojure/clojure/contrib/generic/comparison.clj @@ -0,0 +1,214 @@ +;; Generic interfaces for comparison operations + +;; by Konrad Hinsen +;; last updated May 25, 2010 + +;; Copyright (c) Konrad Hinsen, 2009-2010. All rights reserved. The use +;; and distribution terms for this software are covered by the Eclipse +;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) +;; which can be found in the file epl-v10.html at the root of this +;; distribution. By using this software in any fashion, you are +;; agreeing to be bound by the terms of this license. You must not +;; remove this notice, or any other, from this software. + +(ns + ^{:author "Konrad Hinsen" + :doc "Generic comparison interface + This library defines generic versions of = < > <= >= zero? + as multimethods that can be defined for any type. Of the + greater/less-than relations, types must minimally implement >."} + clojure.contrib.generic.comparison + (:refer-clojure :exclude [= < > <= >= zero? pos? neg? min max]) + (:use [clojure.contrib.generic + :only (root-type nulary-type nary-type nary-dispatch)])) + +; +; zero? pos? neg? +; +(defmulti zero? + "Return true of x is zero." + {:arglists '([x])} + type) + +(defmulti pos? + "Return true of x is positive." + {:arglists '([x])} + type) + +(defmulti neg? + "Return true of x is negative." + {:arglists '([x])} + type) + +; +; Equality +; +(defmulti = + "Return true if all arguments are equal. The minimal implementation for type + ::my-type is the binary form with dispatch value [::my-type ::my-type]." + {:arglists '([x] [x y] [x y & more])} + nary-dispatch) + +(defmethod = root-type + [x] true) + +(defmethod = nary-type + [x y & more] + (if (= x y) + (if (next more) + (recur y (first more) (next more)) + (= y (first more))) + false)) + +; +; Greater-than +; +(defmulti > + "Return true if each argument is larger than the following ones. + The minimal implementation for type ::my-type is the binary form + with dispatch value [::my-type ::my-type]." + {:arglists '([x] [x y] [x y & more])} + nary-dispatch) + +(defmethod > root-type + [x] true) + +(defmethod > nary-type + [x y & more] + (if (> x y) + (if (next more) + (recur y (first more) (next more)) + (> y (first more))) + false)) + +; +; Less-than defaults to greater-than with arguments inversed +; +(defmulti < + "Return true if each argument is smaller than the following ones. + The minimal implementation for type ::my-type is the binary form + with dispatch value [::my-type ::my-type]. A default implementation + is provided in terms of >." + {:arglists '([x] [x y] [x y & more])} + nary-dispatch) + +(defmethod < root-type + [x] true) + +(defmethod < [root-type root-type] + [x y] + (> y x)) + +(defmethod < nary-type + [x y & more] + (if (< x y) + (if (next more) + (recur y (first more) (next more)) + (< y (first more))) + false)) + +; +; Greater-or-equal defaults to (complement <) +; +(defmulti >= + "Return true if each argument is larger than or equal to the following + ones. The minimal implementation for type ::my-type is the binary form + with dispatch value [::my-type ::my-type]. A default implementation + is provided in terms of <." + {:arglists '([x] [x y] [x y & more])} + nary-dispatch) + +(defmethod >= root-type + [x] true) + +(defmethod >= [root-type root-type] + [x y] + (not (< x y))) + +(defmethod >= nary-type + [x y & more] + (if (>= x y) + (if (next more) + (recur y (first more) (next more)) + (>= y (first more))) + false)) + +; +; Less-than defaults to (complement >) +; +(defmulti <= + "Return true if each arguments is smaller than or equal to the following + ones. The minimal implementation for type ::my-type is the binary form + with dispatch value [::my-type ::my-type]. A default implementation + is provided in terms of >." + {:arglists '([x] [x y] [x y & more])} + nary-dispatch) + +(defmethod <= root-type + [x] true) + +(defmethod <= [root-type root-type] + [x y] + (not (> x y))) + +(defmethod <= nary-type + [x y & more] + (if (<= x y) + (if (next more) + (recur y (first more) (next more)) + (<= y (first more))) + false)) + +; +; Implementations for Clojure's built-in types +; +(defmethod zero? java.lang.Number + [x] + (clojure.core/zero? x)) + +(defmethod pos? java.lang.Number + [x] + (clojure.core/pos? x)) + +(defmethod neg? java.lang.Number + [x] + (clojure.core/neg? x)) + +(defmethod = [Object Object] + [x y] + (clojure.core/= x y)) + +(defmethod > [java.lang.Number java.lang.Number] + [x y] + (clojure.core/> x y)) + +(defmethod < [java.lang.Number java.lang.Number] + [x y] + (clojure.core/< x y)) + +(defmethod >= [java.lang.Number java.lang.Number] + [x y] + (clojure.core/>= x y)) + +(defmethod <= [java.lang.Number java.lang.Number] + [x y] + (clojure.core/<= x y)) + +; +; Functions defined in terms of the comparison operators +; +(defn max + "Returns the greatest of its arguments. Like clojure.core/max except that + is uses generic comparison functions implementable for any data type." + ([x] x) + ([x y] (if (> x y) x y)) + ([x y & more] + (reduce max (max x y) more))) + +(defn min + "Returns the least of its arguments. Like clojure.core/min except that + is uses generic comparison functions implementable for any data type." + ([x] x) + ([x y] (if (< x y) x y)) + ([x y & more] + (reduce min (min x y) more))) diff --git a/modules/generic/src/main/clojure/clojure/contrib/generic/functor.clj b/modules/generic/src/main/clojure/clojure/contrib/generic/functor.clj new file mode 100644 index 00000000..4728eaab --- /dev/null +++ b/modules/generic/src/main/clojure/clojure/contrib/generic/functor.clj @@ -0,0 +1,40 @@ +;; Generic interface for functors + +;; by Konrad Hinsen +;; last updated May 3, 2009 + +;; Copyright (c) Konrad Hinsen, 2009. All rights reserved. The use +;; and distribution terms for this software are covered by the Eclipse +;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) +;; which can be found in the file epl-v10.html at the root of this +;; distribution. By using this software in any fashion, you are +;; agreeing to be bound by the terms of this license. You must not +;; remove this notice, or any other, from this software. + +(ns + ^{:author "Konrad Hinsen" + :doc "Generic functor interface (fmap)"} + clojure.contrib.generic.functor) + + +(defmulti fmap + "Applies function f to each item in the data structure s and returns + a structure of the same kind." + {:arglists '([f s])} + (fn [f s] (type s))) + +(defmethod fmap clojure.lang.IPersistentList + [f v] + (into (empty v) (map f v))) + +(defmethod fmap clojure.lang.IPersistentVector + [f v] + (into (empty v) (map f v))) + +(defmethod fmap clojure.lang.IPersistentMap + [f m] + (into (empty m) (for [[k v] m] [k (f v)]))) + +(defmethod fmap clojure.lang.IPersistentSet + [f s] + (into (empty s) (map f s))) diff --git a/modules/generic/src/main/clojure/clojure/contrib/generic/math_functions.clj b/modules/generic/src/main/clojure/clojure/contrib/generic/math_functions.clj new file mode 100644 index 00000000..c0918840 --- /dev/null +++ b/modules/generic/src/main/clojure/clojure/contrib/generic/math_functions.clj @@ -0,0 +1,114 @@ +;; Generic interfaces for mathematical functions + +;; by Konrad Hinsen +;; last updated May 5, 2009 + +;; Copyright (c) Konrad Hinsen, 2009. All rights reserved. The use +;; and distribution terms for this software are covered by the Eclipse +;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) +;; which can be found in the file epl-v10.html at the root of this +;; distribution. By using this software in any fashion, you are +;; agreeing to be bound by the terms of this license. You must not +;; remove this notice, or any other, from this software. + +(ns + ^{:author "Konrad Hinsen" + :doc "Generic math function interface + This library defines generic versions of common mathematical + functions such as sqrt or sin as multimethods that can be + defined for any type."} + clojure.contrib.generic.math-functions + (:use [clojure.contrib.def :only (defmacro-)]) + (:require [clojure.contrib.generic.arithmetic :as ga] + [clojure.contrib.generic.comparison :as gc])) + +(defmacro- defmathfn-1 + [name] + (let [java-symbol (symbol "java.lang.Math" (str name))] + `(do + (defmulti ~name + ~(str "Return the " name " of x.") + {:arglists '([~'x])} + type) + (defmethod ~name java.lang.Number + [~'x] + (~java-symbol ~'x))))) + +(defn- two-types [x y] [(type x) (type y)]) + +(defmacro- defmathfn-2 + [name] + (let [java-symbol (symbol "java.lang.Math" (str name))] + `(do + (defmulti ~name + ~(str "Return the " name " of x and y.") + {:arglists '([~'x ~'y])} + two-types) + (defmethod ~name [java.lang.Number java.lang.Number] + [~'x ~'y] + (~java-symbol ~'x ~'y))))) + +; List of math functions taken from +; http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Math.html +(defmathfn-1 abs) +(defmathfn-1 acos) +(defmathfn-1 asin) +(defmathfn-1 atan) +(defmathfn-2 atan2) +(defmathfn-1 ceil) +(defmathfn-1 cos) +(defmathfn-1 exp) +(defmathfn-1 floor) +(defmathfn-1 log) +(defmathfn-2 pow) +(defmathfn-1 rint) +(defmathfn-1 round) +(defmathfn-1 sin) +(defmathfn-1 sqrt) +(defmathfn-1 tan) + +; +; Sign +; +(defmulti sgn + "Return the sign of x (-1, 0, or 1)." + {:arglists '([x])} + type) + +(defmethod sgn :default + [x] + (cond (gc/zero? x) 0 + (gc/> x 0) 1 + :else -1)) + +; +; Conjugation +; +(defmulti conjugate + "Return the conjugate of x." + {:arglists '([x])} + type) + +(defmethod conjugate :default + [x] x) + +; +; Square +; +(defmulti sqr + "Return the square of x." + {:arglists '([x])} + type) + +(defmethod sqr :default + [x] + (ga/* x x)) + +; +; Approximate equality for use with floating point types +; +(defn approx= + "Return true if the absolute value of the difference between x and y + is less than eps." + [x y eps] + (gc/< (abs (ga/- x y)) eps)) |