rlm@10
|
1 ;; Generic interfaces for arithmetic operations
|
rlm@10
|
2
|
rlm@10
|
3 ;; by Konrad Hinsen
|
rlm@10
|
4 ;; last updated May 5, 2009
|
rlm@10
|
5
|
rlm@10
|
6 ;; Copyright (c) Konrad Hinsen, 2009. All rights reserved. The use
|
rlm@10
|
7 ;; and distribution terms for this software are covered by the Eclipse
|
rlm@10
|
8 ;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
|
rlm@10
|
9 ;; which can be found in the file epl-v10.html at the root of this
|
rlm@10
|
10 ;; distribution. By using this software in any fashion, you are
|
rlm@10
|
11 ;; agreeing to be bound by the terms of this license. You must not
|
rlm@10
|
12 ;; remove this notice, or any other, from this software.
|
rlm@10
|
13
|
rlm@10
|
14 (ns
|
rlm@10
|
15 ^{:author "Konrad Hinsen"
|
rlm@10
|
16 :doc "Generic arithmetic interface
|
rlm@10
|
17 This library defines generic versions of + - * / as multimethods
|
rlm@10
|
18 that can be defined for any type. The minimal required
|
rlm@10
|
19 implementations for a type are binary + and * plus unary - and /.
|
rlm@10
|
20 Everything else is derived from these automatically. Explicit
|
rlm@10
|
21 binary definitions for - and / can be provided for
|
rlm@10
|
22 efficiency reasons."}
|
rlm@10
|
23 clojure.contrib.generic.arithmetic
|
rlm@10
|
24 (:use [clojure.contrib.generic
|
rlm@10
|
25 :only (root-type nulary-type nary-type nary-dispatch)]
|
rlm@10
|
26 [clojure.contrib.types :only (defadt)])
|
rlm@10
|
27 (:refer-clojure :exclude [+ - * /]))
|
rlm@10
|
28
|
rlm@10
|
29 ;
|
rlm@10
|
30 ; Universal zero and one values
|
rlm@10
|
31 ;
|
rlm@10
|
32 (defadt ::zero zero)
|
rlm@10
|
33 (defadt ::one one)
|
rlm@10
|
34
|
rlm@10
|
35 (derive ::zero root-type)
|
rlm@10
|
36 (derive ::one root-type)
|
rlm@10
|
37
|
rlm@10
|
38 ;
|
rlm@10
|
39 ; Addition
|
rlm@10
|
40 ;
|
rlm@10
|
41 ; The minimal implementation is for binary my-type. It is possible
|
rlm@10
|
42 ; in principle to implement [::unary my-type] as well, though this
|
rlm@10
|
43 ; doesn't make any sense.
|
rlm@10
|
44 ;
|
rlm@10
|
45 (defmulti +
|
rlm@10
|
46 "Return the sum of all arguments. The minimal implementation for type
|
rlm@10
|
47 ::my-type is the binary form with dispatch value [::my-type ::my-type]."
|
rlm@10
|
48 {:arglists '([x] [x y] [x y & more])}
|
rlm@10
|
49 nary-dispatch)
|
rlm@10
|
50
|
rlm@10
|
51 (defmethod + nulary-type
|
rlm@10
|
52 []
|
rlm@10
|
53 zero)
|
rlm@10
|
54
|
rlm@10
|
55 (defmethod + root-type
|
rlm@10
|
56 [x] x)
|
rlm@10
|
57
|
rlm@10
|
58 (defmethod + [root-type ::zero]
|
rlm@10
|
59 [x y] x)
|
rlm@10
|
60
|
rlm@10
|
61 (defmethod + [::zero root-type]
|
rlm@10
|
62 [x y] y)
|
rlm@10
|
63
|
rlm@10
|
64 (defmethod + nary-type
|
rlm@10
|
65 [x y & more]
|
rlm@10
|
66 (if more
|
rlm@10
|
67 (recur (+ x y) (first more) (next more))
|
rlm@10
|
68 (+ x y)))
|
rlm@10
|
69
|
rlm@10
|
70 ;
|
rlm@10
|
71 ; Subtraction
|
rlm@10
|
72 ;
|
rlm@10
|
73 ; The minimal implementation is for unary my-type. A default binary
|
rlm@10
|
74 ; implementation is provided as (+ x (- y)), but it is possible to
|
rlm@10
|
75 ; implement unary my-type explicitly for efficiency reasons.
|
rlm@10
|
76 ;
|
rlm@10
|
77 (defmulti -
|
rlm@10
|
78 "Return the difference of the first argument and the sum of all other
|
rlm@10
|
79 arguments. The minimal implementation for type ::my-type is the binary
|
rlm@10
|
80 form with dispatch value [::my-type ::my-type]."
|
rlm@10
|
81 {:arglists '([x] [x y] [x y & more])}
|
rlm@10
|
82 nary-dispatch)
|
rlm@10
|
83
|
rlm@10
|
84 (defmethod - nulary-type
|
rlm@10
|
85 []
|
rlm@10
|
86 (throw (java.lang.IllegalArgumentException.
|
rlm@10
|
87 "Wrong number of arguments passed")))
|
rlm@10
|
88
|
rlm@10
|
89 (defmethod - [root-type ::zero]
|
rlm@10
|
90 [x y] x)
|
rlm@10
|
91
|
rlm@10
|
92 (defmethod - [::zero root-type]
|
rlm@10
|
93 [x y] (- y))
|
rlm@10
|
94
|
rlm@10
|
95 (defmethod - [root-type root-type]
|
rlm@10
|
96 [x y] (+ x (- y)))
|
rlm@10
|
97
|
rlm@10
|
98 (defmethod - nary-type
|
rlm@10
|
99 [x y & more]
|
rlm@10
|
100 (if more
|
rlm@10
|
101 (recur (- x y) (first more) (next more))
|
rlm@10
|
102 (- x y)))
|
rlm@10
|
103
|
rlm@10
|
104 ;
|
rlm@10
|
105 ; Multiplication
|
rlm@10
|
106 ;
|
rlm@10
|
107 ; The minimal implementation is for binary [my-type my-type]. It is possible
|
rlm@10
|
108 ; in principle to implement unary my-type as well, though this
|
rlm@10
|
109 ; doesn't make any sense.
|
rlm@10
|
110 ;
|
rlm@10
|
111 (defmulti *
|
rlm@10
|
112 "Return the product of all arguments. The minimal implementation for type
|
rlm@10
|
113 ::my-type is the binary form with dispatch value [::my-type ::my-type]."
|
rlm@10
|
114 {:arglists '([x] [x y] [x y & more])}
|
rlm@10
|
115 nary-dispatch)
|
rlm@10
|
116
|
rlm@10
|
117 (defmethod * nulary-type
|
rlm@10
|
118 []
|
rlm@10
|
119 one)
|
rlm@10
|
120
|
rlm@10
|
121 (defmethod * root-type
|
rlm@10
|
122 [x] x)
|
rlm@10
|
123
|
rlm@10
|
124 (defmethod * [root-type ::one]
|
rlm@10
|
125 [x y] x)
|
rlm@10
|
126
|
rlm@10
|
127 (defmethod * [::one root-type]
|
rlm@10
|
128 [x y] y)
|
rlm@10
|
129
|
rlm@10
|
130 (defmethod * nary-type
|
rlm@10
|
131 [x y & more]
|
rlm@10
|
132 (if more
|
rlm@10
|
133 (recur (* x y) (first more) (next more))
|
rlm@10
|
134 (* x y)))
|
rlm@10
|
135
|
rlm@10
|
136 ;
|
rlm@10
|
137 ; Division
|
rlm@10
|
138 ;
|
rlm@10
|
139 ; The minimal implementation is for unary my-type. A default binary
|
rlm@10
|
140 ; implementation is provided as (* x (/ y)), but it is possible to
|
rlm@10
|
141 ; implement binary [my-type my-type] explicitly for efficiency reasons.
|
rlm@10
|
142 ;
|
rlm@10
|
143 (defmulti /
|
rlm@10
|
144 "Return the quotient of the first argument and the product of all other
|
rlm@10
|
145 arguments. The minimal implementation for type ::my-type is the binary
|
rlm@10
|
146 form with dispatch value [::my-type ::my-type]."
|
rlm@10
|
147 {:arglists '([x] [x y] [x y & more])}
|
rlm@10
|
148 nary-dispatch)
|
rlm@10
|
149
|
rlm@10
|
150 (defmethod / nulary-type
|
rlm@10
|
151 []
|
rlm@10
|
152 (throw (java.lang.IllegalArgumentException.
|
rlm@10
|
153 "Wrong number of arguments passed")))
|
rlm@10
|
154
|
rlm@10
|
155 (defmethod / [root-type ::one]
|
rlm@10
|
156 [x y] x)
|
rlm@10
|
157
|
rlm@10
|
158 (defmethod / [::one root-type]
|
rlm@10
|
159 [x y] (/ y))
|
rlm@10
|
160
|
rlm@10
|
161 (defmethod / [root-type root-type]
|
rlm@10
|
162 [x y] (* x (/ y)))
|
rlm@10
|
163
|
rlm@10
|
164 (defmethod / nary-type
|
rlm@10
|
165 [x y & more]
|
rlm@10
|
166 (if more
|
rlm@10
|
167 (recur (/ x y) (first more) (next more))
|
rlm@10
|
168 (/ x y)))
|
rlm@10
|
169
|
rlm@10
|
170 ;
|
rlm@10
|
171 ; Macros to permit access to the / multimethod via namespace qualification
|
rlm@10
|
172 ;
|
rlm@10
|
173 (defmacro defmethod*
|
rlm@10
|
174 "Define a method implementation for the multimethod name in namespace ns.
|
rlm@10
|
175 Required for implementing the division function from another namespace."
|
rlm@10
|
176 [ns name & args]
|
rlm@10
|
177 (let [qsym (symbol (str ns) (str name))]
|
rlm@10
|
178 `(defmethod ~qsym ~@args)))
|
rlm@10
|
179
|
rlm@10
|
180 (defmacro qsym
|
rlm@10
|
181 "Create the qualified symbol corresponding to sym in namespace ns.
|
rlm@10
|
182 Required to access the division function from another namespace,
|
rlm@10
|
183 e.g. as (qsym clojure.contrib.generic.arithmetic /)."
|
rlm@10
|
184 [ns sym]
|
rlm@10
|
185 (symbol (str ns) (str sym)))
|
rlm@10
|
186
|
rlm@10
|
187 ;
|
rlm@10
|
188 ; Minimal implementations for java.lang.Number
|
rlm@10
|
189 ;
|
rlm@10
|
190 (defmethod + [java.lang.Number java.lang.Number]
|
rlm@10
|
191 [x y] (clojure.core/+ x y))
|
rlm@10
|
192
|
rlm@10
|
193 (defmethod - java.lang.Number
|
rlm@10
|
194 [x] (clojure.core/- x))
|
rlm@10
|
195
|
rlm@10
|
196 (defmethod * [java.lang.Number java.lang.Number]
|
rlm@10
|
197 [x y] (clojure.core/* x y))
|
rlm@10
|
198
|
rlm@10
|
199 (defmethod / java.lang.Number
|
rlm@10
|
200 [x] (clojure.core// x))
|
rlm@10
|
201
|