Permalink
Browse files

reduce can be terminated via (reduced x), first cut at reduce lib

  • Loading branch information...
1 parent 96e8596 commit 4a22e3a44df48ea0d37dd034bc3f6cb3092117a9 @richhickey richhickey committed Apr 30, 2012
Showing with 140 additions and 4 deletions.
  1. +131 −0 src/clj/clojure/core/reduce.clj
  2. +9 −4 src/jvm/clojure/lang/Reduced.java
@@ -0,0 +1,131 @@
+; Copyright (c) Rich Hickey. 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.core.reduce
+ (:refer-clojure :exclude [map filter remove take take-while drop flatten]))
+
+(set! *warn-on-reflection* true)
+
+(defn reducer
+ "Given a reducible collection, and a transformation function xf,
+ returns a reducible collection, where any supplied reducing
+ fn will be transformed by xf. xf is a function of reducing fn to
+ reducing fn."
+ {:added "1.5"}
+ [coll xf]
+ (reify clojure.core.protocols/CollReduce
+ (coll-reduce [_ f1]
+ (throw (Exception. "You must supply an init value for reducer-based reduce")))
+ (coll-reduce [_ f1 init]
+ (clojure.core.protocols/coll-reduce coll (xf f1) init))))
+
+(defn map
+ "Applies f to every value in the reduction of coll"
+ {:added "1.5"}
+ [f coll]
+ (reducer
+ coll
+ (fn [f1]
+ (fn [ret v] (f1 ret (f v))))))
+
+(defn filter
+ "Retains values in the reduction of coll for which (pred val) returns logical true"
+ {:added "1.5"}
+ [pred coll]
+ (reducer
+ coll
+ (fn [f1]
+ (fn [ret v]
+ (if (pred v)
+ (f1 ret v)
+ ret)))))
+
+(defn remove
+ "Removes values in the reduction of coll for which (pred val) returns logical true"
+ {:added "1.5"}
+ [pred coll]
+ (filter (complement pred) coll))
+
+(defn take-while
+ "Ends the reduction of coll when (pred val) returns logical false."
+ {:added "1.5"}
+ [pred coll]
+ (reducer
+ coll
+ (fn [f1]
+ (fn [ret v]
+ (if (pred v)
+ (f1 ret v)
+ (reduced ret))))))
+
+(defn take
+ "Ends the reduction of coll after consuming n values."
+ {:added "1.5"}
+ [n coll]
+ (reducer
+ coll
+ (fn [f1]
+ (let [cnt (atom n)]
+ (fn [ret v]
+ (swap! cnt dec)
+ (if (neg? @cnt)
+ (reduced ret)
+ (f1 ret v)))))))
+
+(defn drop
+ "Elides the first n values from the reduction of coll."
+ {:added "1.5"}
+ [n coll]
+ (reducer
+ coll
+ (fn [f1]
+ (let [cnt (atom n)]
+ (fn [ret v]
+ (swap! cnt dec)
+ (if (neg? @cnt)
+ (f1 ret v)
+ ret))))))
+
+(defn flatten
+ "Takes any nested combination of sequential things (lists, vectors,
+ etc.) and returns their contents as a single, flat reducible
+ collection."
+ {:added "1.5"}
+ [coll]
+ (reify clojure.core.protocols/CollReduce
+ (coll-reduce [_ f1]
+ (throw (Exception. "You must supply an init value for reducer-based reduce")))
+ (coll-reduce [_ f1 init]
+ (clojure.core.protocols/coll-reduce
+ coll
+ (fn [ret v]
+ (if (sequential? v)
+ (clojure.core.protocols/coll-reduce (flatten v) f1 ret)
+ (f1 ret v)))
+ init))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+(comment
+(require '[clojure.core.reduce :as r])
+(def v (take 1000000 (range)))
+(reduce + 0 (r/map inc [1 2 3 4]))
+(into [] (r/take 12 (range 100)))
+(into [] (r/drop 12 (range 100)))
+(reduce + 0 (r/filter even? [1 2 3 4]))
+(into [] (r/filter even? [1 2 3 4]))
+(reduce + (filter even? [1 2 3 4]))
+(dotimes [_ 10] (time (reduce + 0 (r/map inc v))))
+(dotimes [_ 10] (time (reduce + 0 (map inc v))))
+(dotimes [_ 100] (time (reduce + 0 v)))
+(dotimes [_ 100] (time (reduce + 0 v)))
+(dotimes [_ 20] (time (reduce + 0 (r/map inc (r/filter even? v)))))
+(dotimes [_ 20] (time (reduce + 0 (map inc (filter even? v)))))
+(reduce + 0 (r/take-while even? [2 4 3]))
+(into [] (r/filter even? (r/flatten (r/remove #{4} [[1 2 3] 4 [5 [6 7 8]] [9] 10]))))
+(into [] (r/flatten nil))
+)
@@ -1,7 +1,12 @@
-// Copyright (c) Metadata Partners, LLC.
-// All rights reserved.
-
-/* rich 4/30/12 */
+/**
+ * Copyright (c) Rich Hickey. 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.
+ **/
package clojure.lang;

0 comments on commit 4a22e3a

Please sign in to comment.