aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build.xml1
-rw-r--r--src/clojure/contrib/gen_html_docs.clj1
-rw-r--r--src/clojure/contrib/generic/collection.clj140
-rw-r--r--src/clojure/contrib/load_all.clj1
-rw-r--r--src/clojure/contrib/stream_utils.clj12
-rw-r--r--src/clojure/contrib/stream_utils/examples.clj28
-rw-r--r--src/clojure/contrib/types/examples.clj50
7 files changed, 177 insertions, 56 deletions
diff --git a/build.xml b/build.xml
index 8ae48ab5..524cfb57 100644
--- a/build.xml
+++ b/build.xml
@@ -85,6 +85,7 @@
<arg value="clojure.contrib.except"/>
<arg value="clojure.contrib.fcase"/>
<arg value="clojure.contrib.generic.arithmetic"/>
+ <arg value="clojure.contrib.generic.collection"/>
<arg value="clojure.contrib.generic.math-functions"/>
<arg value="clojure.contrib.import-static"/>
<arg value="clojure.contrib.javadoc.browse"/>
diff --git a/src/clojure/contrib/gen_html_docs.clj b/src/clojure/contrib/gen_html_docs.clj
index 7a587fdf..c00d3513 100644
--- a/src/clojure/contrib/gen_html_docs.clj
+++ b/src/clojure/contrib/gen_html_docs.clj
@@ -483,6 +483,7 @@ emits the generated HTML to the path named by path."
'clojure.contrib.except
'clojure.contrib.fcase
'clojure.contrib.generic.arithmetic
+ 'clojure.contrib.generic.collection
'clojure.contrib.generic.math-functions
'clojure.contrib.import-static
'clojure.contrib.javadoc
diff --git a/src/clojure/contrib/generic/collection.clj b/src/clojure/contrib/generic/collection.clj
new file mode 100644
index 00000000..53e316a3
--- /dev/null
+++ b/src/clojure/contrib/generic/collection.clj
@@ -0,0 +1,140 @@
+;; Generic interfaces for collection-related functions
+
+;; by Konrad Hinsen
+;; last updated March 16, 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 clojure.contrib.generic.collection
+ "Generic collection function interface
+
+ NOTE: This library is VERY experimental. It WILL change significantly
+ with future release.
+
+ This library defines generic versions of common collection-related functions
+ such as map or conj as multimethods that can be defined for any type."
+ (:refer-clojure :exclude [assoc conj dissoc empty get into map 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 (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
+;
+; This is a literal copy of into from clojure.core, but it is
+; evaluated with the functions from this namespace here!
+(declare seq)
+(defn into
+ "Returns a new coll consisting of to-coll with all of the items of
+ from-coll conjoined."
+ [to from]
+ (let [ret to items (seq from)]
+ (if items
+ (recur (conj ret (first items)) (next items))
+ ret)))
+
+;
+; map
+;
+(defmulti map
+ "Applies function f to each element of coll and returns a collection
+ of the same kind as coll."
+ {:arglists '([f coll])}
+ (fn [f coll] (type coll)))
+
+(defmethod map clojure.lang.ISeq
+ [f coll]
+ (clojure.core/map f coll))
+
+(defmethod map clojure.lang.IPersistentVector
+ [f v]
+ (clojure.core/into (clojure.core/empty v) (clojure.core/map f v)))
+
+(defmethod map clojure.lang.IPersistentMap
+ [f m]
+ (clojure.core/into (clojure.core/empty m) (for [[k v] m] [k (f v)])))
+
+(defmethod map clojure.lang.IPersistentSet
+ [f s]
+ (clojure.core/into (clojure.core/empty s) (clojure.core/map f s)))
+
+;
+; seq
+;
+(defmulti seq
+ "Returns a seq on the object s."
+ {:arglists '([s])}
+ type)
+
+(defmethod seq :default
+ [s]
+ (clojure.core/seq s))
diff --git a/src/clojure/contrib/load_all.clj b/src/clojure/contrib/load_all.clj
index 9593e2ce..9890803d 100644
--- a/src/clojure/contrib/load_all.clj
+++ b/src/clojure/contrib/load_all.clj
@@ -43,6 +43,7 @@ error-kit
except
fcase
generic.arithmetic
+generic.collection
generic.math-functions
import-static
javadoc.browse
diff --git a/src/clojure/contrib/stream_utils.clj b/src/clojure/contrib/stream_utils.clj
index 7ce9933f..15761771 100644
--- a/src/clojure/contrib/stream_utils.clj
+++ b/src/clojure/contrib/stream_utils.clj
@@ -1,7 +1,7 @@
;; Stream utilities
;; by Konrad Hinsen
-;; last updated March 12, 2009
+;; last updated March 16, 2009
;; Copyright (c) Konrad Hinsen, 2009. All rights reserved. The use
;; and distribution terms for this software are covered by the Eclipse
@@ -56,7 +56,8 @@
(:use [clojure.contrib.types :only (deftype deftype-)])
(:use [clojure.contrib.monads :only (defmonad with-monad)])
(:use [clojure.contrib.def :only (defvar defvar-)])
- (:require [clojure.contrib.seq-utils]))
+ (:require [clojure.contrib.seq-utils])
+ (:require [clojure.contrib.generic.collection]))
;
@@ -108,7 +109,8 @@
(defn stream-seq
"Return a lazy seq on the stream. Also accessible via
- clojure.contrib.seq-utils/seq-on for streams."
+ clojure.contrib.seq-utils/seq-on and
+ clojure.contrib.generic.collection/seq for streams."
[s]
(lazy-seq
(let [[v ns] (stream-next s)]
@@ -120,6 +122,10 @@
[s]
(stream-seq s))
+(defmethod clojure.contrib.generic.collection/seq stream-type
+ [s]
+ (stream-seq s))
+
;
; Stream transformers
;
diff --git a/src/clojure/contrib/stream_utils/examples.clj b/src/clojure/contrib/stream_utils/examples.clj
index 10207fff..5b98c65f 100644
--- a/src/clojure/contrib/stream_utils/examples.clj
+++ b/src/clojure/contrib/stream_utils/examples.clj
@@ -13,8 +13,8 @@
stream-type defstream
stream-drop stream-map stream-filter stream-flatten)])
(:use [clojure.contrib.monads :only (domonad)])
- (:use [clojure.contrib.seq-utils :only (seq-on)])
- (:use [clojure.contrib.types :only (deftype)]))
+ (:use [clojure.contrib.types :only (deftype)])
+ (:require [clojure.contrib.generic.collection :as gc]))
;
; Define a stream of Fibonacci numbers
@@ -28,7 +28,7 @@
(def fib-stream (last-two-fib [0 1]))
-(take 10 (seq-on fib-stream))
+(take 10 (gc/seq fib-stream))
;
; A simple random number generator, implemented as a stream
@@ -43,15 +43,15 @@
next (rem (+ 54773 (* 7141 seed)) m)]
[value (rng-seed next)]))
-(take 10 (seq-on (rng-seed 1)))
+(take 10 (gc/seq (rng-seed 1)))
;
; Various stream utilities
;
-(take 10 (seq-on (stream-drop 10 (rng-seed 1))))
-(seq-on (stream-map inc (range 5)))
-(seq-on (stream-filter odd? (range 10)))
-(seq-on (stream-flatten (partition 3 (range 9))))
+(take 10 (gc/seq (stream-drop 10 (rng-seed 1))))
+(gc/seq (stream-map inc (range 5)))
+(gc/seq (stream-filter odd? (range 10)))
+(gc/seq (stream-flatten (partition 3 (range 9))))
;
; Stream transformers
@@ -74,7 +74,7 @@
(let [[v5 s] (stream-next s)]
[v1 v2 v3 v4 v5])))))
-(seq-on s)
+(gc/seq s)
; Map (for a single stream) written as a stream transformer
(defst my-map-1 [f] [xs]
@@ -82,7 +82,7 @@
[x (pick xs)]
(f x)))
-(seq-on (my-map-1 inc [1 2 3]))
+(gc/seq (my-map-1 inc [1 2 3]))
; Map for two stream arguments
(defst my-map-2 [f] [xs ys]
@@ -91,7 +91,7 @@
y (pick ys)]
(f x y)))
-(seq-on (my-map-2 + '(1 2 3 4) '(10 20 30 40)))
+(gc/seq (my-map-2 + '(1 2 3 4) '(10 20 30 40)))
; Map for any number of stream arguments
(defst my-map [f] [& streams]
@@ -99,8 +99,8 @@
[vs pick-all]
(apply f vs)))
-(seq-on (my-map inc [1 2 3]))
-(seq-on (my-map + '(1 2 3 4) '(10 20 30 40)))
+(gc/seq (my-map inc [1 2 3]))
+(gc/seq (my-map + '(1 2 3 4) '(10 20 30 40)))
; Filter written as a stream transformer
(defst my-filter [p] [xs]
@@ -108,5 +108,5 @@
[x (pick xs) :when (p x)]
x))
-(seq-on (my-filter odd? [1 2 3]))
+(gc/seq (my-filter odd? [1 2 3]))
diff --git a/src/clojure/contrib/types/examples.clj b/src/clojure/contrib/types/examples.clj
index 8f4f98e4..214f7e1c 100644
--- a/src/clojure/contrib/types/examples.clj
+++ b/src/clojure/contrib/types/examples.clj
@@ -8,7 +8,8 @@
(ns clojure.contrib.types.examples
(:use [clojure.contrib.types
- :only (deftype defadt match)]))
+ :only (deftype defadt match)])
+ (:require [clojure.contrib.generic.collection :as gc]))
;
; Multisets implemented as maps to integers
@@ -19,19 +20,13 @@
(deftype ::multiset multiset)
; Some set operations generalized to multisets
-; Note that the multiset constructor is not called anywhere, as the
+; Note that the multiset constructor is nowhere called explicitly, as the
; map operations all preserve the metadata.
-(defmulti my-conj (fn [& args] (type (first args))))
-
-(defmethod my-conj :default
- [& args]
- (apply clojure.core/conj args))
-
-(defmethod my-conj ::multiset
+(defmethod gc/conj ::multiset
([ms x]
(assoc ms x (inc (get ms x 0))))
([ms x & xs]
- (reduce my-conj (my-conj ms x) xs)))
+ (reduce gc/conj (gc/conj ms x) xs)))
(defmulti union (fn [& sets] (type (first sets))))
@@ -51,8 +46,8 @@
(reduce union (union ms1 ms2) mss)))
; Let's use it:
-(my-conj #{} :a :a :b :c)
-(my-conj (multiset {}) :a :a :b :c)
+(gc/conj #{} :a :a :b :c)
+(gc/conj (multiset {}) :a :a :b :c)
(union #{:a :b} #{:b :c})
(union (multiset {:a 1 :b 1}) (multiset {:b 1 :c 2}))
@@ -79,38 +74,15 @@
(depth empty-tree)
(depth a-tree)
-;
-; Algebraic data types with multimethods: Haskell-style functors
-;
-(defmulti fmap (fn [f s] (type s)))
-
-; Sequences
-(defmethod fmap clojure.lang.ISeq
- [f s]
- (map f s))
-
-; Vectors
-(defmethod fmap clojure.lang.IPersistentVector
- [f v]
- (into [] (map f v)))
-
-; Maps
-(defmethod fmap clojure.lang.IPersistentMap
- [f m]
- (into {} (for [[k v] m] [k (f v)])))
-
-; Trees
-(defmethod fmap ::tree
+; Algebraic data types with multimethods: map on a tree
+(defmethod gc/map ::tree
[f t]
(match t
empty-tree empty-tree
(leaf v) (leaf (f v))
- (node l r) (node (fmap f l) (fmap f r))))
+ (node l r) (node (gc/map f l) (gc/map f r))))
-(fmap str '(:a :b :c))
-(fmap str [:a :b :c])
-(fmap str {:a 1 :b 2 :c 3})
-(fmap str a-tree)
+(gc/map str a-tree)
;
; Nonsense examples to illustrate all the features of match