Skip to content

Instantly share code, notes, and snippets.

@cgrand
Created January 22, 2014 22:31
Show Gist options
  • Save cgrand/8568717 to your computer and use it in GitHub Desktop.
Save cgrand/8568717 to your computer and use it in GitHub Desktop.
Mon historique de l'atelier data vs fns du Paris Clojure User Group http://www.meetup.com/Paris-Clojure-User-Group/ du 22 Janvier 2014
;; Clojure 1.5.1
=> ; coll (fn [f acc]) renvoie (reduce f acc coll)
=> ; coll (fn [f init]) renvoie (reduce f init coll)
=> (defn fnil [f init] init)
WARNING: fnil already refers to: #'clojure.core/fnil in namespace: cljug.core, being replaced by: #'cljug.core/fnil
#'cljug.core/fnil
=> (reduce + 0 nil)
0
=> (fnil + 0)
0
=> (defn fcons [x fcoll]
(fn [f init]
#_(reduce f init (cons x coll))
#_(reduce f (f init x) coll)
(fcoll f (f init x))))
#'cljug.core/fcons
=> (fcons 1 (fcons 2 (fcons 3 fnil)))
#<core$fcons$fn__1571 cljug.core$fcons$fn__1571@ad5da47>
=> (*1 + 0)
6
=> (*2 conj [])
[1 2 3]
=> (defn fcons [head ftail]
(fn [f init]
(ftail f (f init head))))
#'cljug.core/fcons
=> (defn fmap [g fcoll]
(fn [f init]
#_(reduce f init (map g coll))
#_(reduce (fn [acc x] (f acc x)) init (map g coll))
#_(reduce (fn [acc x] (f acc (g x))) init coll)
(fcoll (fn [acc x] (f acc (g x))) init)))
#'cljug.core/fmap
=> (fmap inc (fcons 1 (fcons 2 (fcons 3 fnil))))
#<core$fmap$fn__1844 cljug.core$fmap$fn__1844@2795804b>
=> (*1 conj [])
[2 3 4]
=> (defn ffilter [pred fcoll]
(fn [f init]
#_(reduce f init (filter pred coll))
#_(reduce (fn [acc x] (f acc x)) init (filter pred coll))
#_(reduce (fn [acc x]
(if (pred x)
(f acc x)
acc)) init coll)
(fcoll (fn [acc x]
(if (pred x)
(f acc x)
acc)) init)))
#'cljug.core/ffilter
=> (ffilter odd? (fcons 1 (fcons 2 (fcons 3 fnil))))
#<core$ffilter$fn__2101 cljug.core$ffilter$fn__2101@3f047fc3>
=> (*1 conj [])
[1 3]
=> (fmap inc (ffilter odd? (fcons 1 (fcons 2 (fcons 3 fnil)))))
#<core$fmap$fn__1844 cljug.core$fmap$fn__1844@5c7b1ff8>
=> (*1 conj [])
[2 4]
=> (defn reducer [xf]
(fn [f init]
(fcoll (xf f) init)))
CompilerException java.lang.RuntimeException: Unable to resolve symbol: fcoll in this context, compiling:(NO_SOURCE_PATH:3:5)
=> (defn reducer [xf fcoll]
(fn [f init]
(fcoll (xf f) init)))
#'cljug.core/reducer
=> (defn ffilter2 [pred fcoll]
(reducer (fn [f]
(fn [acc x]
(if (pred x)
(f acc x)
acc)))))
#'cljug.core/ffilter2
=> (fmap inc (ffilter2 odd? (fcons 1 (fcons 2 (fcons 3 fnil)))))
ArityException Wrong number of args (1) passed to: core$reducer clojure.lang.AFn.throwArity (AFn.java:437)
=> (defn ffilter2 [pred fcoll]
(reducer (fn [f]
(fn [acc x]
(if (pred x)
(f acc x)
acc)))
fcoll))
#'cljug.core/ffilter2
=> (fmap inc (ffilter2 odd? (fcons 1 (fcons 2 (fcons 3 fnil)))))
#<core$fmap$fn__1844 cljug.core$fmap$fn__1844@14268c02>
=> (*1 conj [])
[2 4]
=> (defn fmap2 [g fcoll]
(reducer (fn [f]
(fn [acc x]
(f acc (g x))))
fcoll))
#'cljug.core/fmap2
=> ;; similaire code des vrais reducers
=> ;; FIN ETAPE 1
=> (use 'clojure.repl)
nil
=> (doc every-pred)
-------------------------
clojure.core/every-pred
([p] [p1 p2] [p1 p2 p3] [p1 p2 p3 & ps])
Takes a set of predicates and returns a function f that returns true if all of its
composing predicates return a logical true value against all of its arguments, else it returns
false. Note that f is short-circuiting in that it will stop execution on the first
argument that triggers a logical false result against the original predicates.
nil
=> ((every-pred odd? even?) 0)
false
=> ((every-pred odd? even?) 1)
false
=> ((every-pred odd? #(> % 5)) 1)
false
=> ((every-pred odd? #(> % 5)) 20)
false
=> ((every-pred odd? #(> % 5)) 21)
true
=> (defn every-pred [& preds]
(fn [x]
(reduce (fn [acc pred]
(and acc (pred x)))
true preds)))
WARNING: every-pred already refers to: #'clojure.core/every-pred in namespace: cljug.core, being replaced by: #'cljug.core/every-pred
#'cljug.core/every-pred
=> ((every-pred odd? #(> % 5)) 21)
true
=> ((every-pred odd? #(> % 5)) 20)
false
=> ((every-pred odd? #(> % 5)) 1)
false
=> (defn every-pred [& preds]
(fn [x]
(reduce (fn [acc pred]
(if (pred x)
acc ; always true
(reduced false)))
true preds)))
#'cljug.core/every-pred
=> (defn every-pred [& preds]
(fn [x]
(every? (fn [pred] (pred x)) preds)))
#'cljug.core/every-pred
=> ((every-pred odd? #(> % 5)) 1)
false
=> (map (every-pred odd? #(> % 5)) [1 20 21 5])
(false false true false)
=> (source clojure.core/every-pred)
(defn every-pred
"Takes a set of predicates and returns a function f that returns true if all of its
composing predicates return a logical true value against all of its arguments, else it returns
false. Note that f is short-circuiting in that it will stop execution on the first
argument that triggers a logical false result against the original predicates."
{:added "1.3"}
([p]
(fn ep1
([] true)
([x] (boolean (p x)))
([x y] (boolean (and (p x) (p y))))
([x y z] (boolean (and (p x) (p y) (p z))))
([x y z & args] (boolean (and (ep1 x y z)
(every? p args))))))
([p1 p2]
(fn ep2
([] true)
([x] (boolean (and (p1 x) (p2 x))))
([x y] (boolean (and (p1 x) (p1 y) (p2 x) (p2 y))))
([x y z] (boolean (and (p1 x) (p1 y) (p1 z) (p2 x) (p2 y) (p2 z))))
([x y z & args] (boolean (and (ep2 x y z)
(every? #(and (p1 %) (p2 %)) args))))))
([p1 p2 p3]
(fn ep3
([] true)
([x] (boolean (and (p1 x) (p2 x) (p3 x))))
([x y] (boolean (and (p1 x) (p2 x) (p3 x) (p1 y) (p2 y) (p3 y))))
([x y z] (boolean (and (p1 x) (p2 x) (p3 x) (p1 y) (p2 y) (p3 y) (p1 z) (p2 z) (p3 z))))
([x y z & args] (boolean (and (ep3 x y z)
(every? #(and (p1 %) (p2 %) (p3 %)) args))))))
([p1 p2 p3 & ps]
(let [ps (list* p1 p2 p3 ps)]
(fn epn
([] true)
([x] (every? #(% x) ps))
([x y] (every? #(and (% x) (% y)) ps))
([x y z] (every? #(and (% x) (% y) (% z)) ps))
([x y z & args] (boolean (and (epn x y z)
(every? #(every? % args) ps))))))))
nil
=> (ns-unmap *ns* 'every-pred)
nil
=> every-pred
CompilerException java.lang.RuntimeException: Unable to resolve symbol: every-pred in this context, compiling:(NO_SOURCE_PATH:1:42)
=> (source clojure.core/every-pred)
(defn every-pred
"Takes a set of predicates and returns a function f that returns true if all of its
composing predicates return a logical true value against all of its arguments, else it returns
false. Note that f is short-circuiting in that it will stop execution on the first
argument that triggers a logical false result against the original predicates."
{:added "1.3"}
([p]
(fn ep1
([] true)
([x] (boolean (p x)))
([x y] (boolean (and (p x) (p y))))
([x y z] (boolean (and (p x) (p y) (p z))))
([x y z & args] (boolean (and (ep1 x y z)
(every? p args))))))
([p1 p2]
(fn ep2
([] true)
([x] (boolean (and (p1 x) (p2 x))))
([x y] (boolean (and (p1 x) (p1 y) (p2 x) (p2 y))))
([x y z] (boolean (and (p1 x) (p1 y) (p1 z) (p2 x) (p2 y) (p2 z))))
([x y z & args] (boolean (and (ep2 x y z)
(every? #(and (p1 %) (p2 %)) args))))))
([p1 p2 p3]
(fn ep3
([] true)
([x] (boolean (and (p1 x) (p2 x) (p3 x))))
([x y] (boolean (and (p1 x) (p2 x) (p3 x) (p1 y) (p2 y) (p3 y))))
([x y z] (boolean (and (p1 x) (p2 x) (p3 x) (p1 y) (p2 y) (p3 y) (p1 z) (p2 z) (p3 z))))
([x y z & args] (boolean (and (ep3 x y z)
(every? #(and (p1 %) (p2 %) (p3 %)) args))))))
([p1 p2 p3 & ps]
(let [ps (list* p1 p2 p3 ps)]
(fn epn
([] true)
([x] (every? #(% x) ps))
([x y] (every? #(and (% x) (% y)) ps))
([x y z] (every? #(and (% x) (% y) (% z)) ps))
([x y z & args] (boolean (and (epn x y z)
(every? #(every? % args) ps))))))))
nil
=> (defn every-pred [& preds]
(fn [x]
(every? (fn [pred] (pred x)) preds)))
#'cljug.core/every-pred
=> (defn every-pred [& preds]
(reduce (fn [juxt-pred pred]
(fn [x]
(and (juxt-pred x) (pred x))))
(constantly true) preds))
#'cljug.core/every-pred
=> (map (every-pred odd? #(> % 5)) [1 20 21 5])
(false false true false)
=> (defn every-pred [& preds]
(reduce (fn [juxt-pred pred]
(fn [x]
(and (juxt-pred x) (pred x))))
(constantly true) preds))
#'cljug.core/every-pred
=> ;; FIN ETAPE 2
=> (defn comp [& fs]
(fn [x]
(reduce (fn [x f] (f x)) x (reverse fs))))
WARNING: comp already refers to: #'clojure.core/comp in namespace: cljug.core, being replaced by: #'cljug.core/comp
#'cljug.core/comp
=> (defn comp [& fs]
(reduce (fn [comp-f f]
(fn [x]
(f (comp-f x))))
identity (reverse fs)))
#'cljug.core/comp
=> ((comp inc #(* 2 %)) 1)
3
=> (defn comp [& fs]
(reduce (fn [comp-f f]
(fn [x]
(comp-f (f x))))
identity fs))
#'cljug.core/comp
=> ((comp inc #(* 2 %)) 1)
3
=> (partition-all (range 5))
ArityException Wrong number of args (1) passed to: core$partition-all clojure.lang.AFn.throwArity (AFn.java:437)
=> (partition-all 2 (range 5))
((0 1) (2 3) (4))
=> (defn comp [& fs]
(letfn [(group [fs]
(let [fs (map (fn [[f g :as fs]]
(if (next fs)
(fn [x] (f (g x)))
f))
(partition-all 2 fs))]
(if (next fs)
(recur fs)
(first fs))))]
(apply group fs)))
#'cljug.core/comp
=> ((comp inc #(* 2 %) dec) 1)
ArityException Wrong number of args (3) passed to: core$comp$group clojure.lang.AFn.throwArity (AFn.java:437)
=> (defn comp [& fs]
(letfn [(group [fs]
(let [fs (map (fn [[f g :as fs]]
(if (next fs)
(fn [x] (f (g x)))
f))
(partition-all 2 fs))]
(if (next fs)
(recur fs)
(first fs))))]
(group fs)))
#'cljug.core/comp
=> ((comp inc #(* 2 %) dec) 1)
1
=> ((comp inc #(* 2 %) dec) 10)
19
=> (defrecord Comp [fs]
clojure.lang.IFn
(invoke [_ x]
(reduce (fn [x f] (f x)) x (rseq fs))))
cljug.core.Comp
=> (defprotocol Composable
(compj [f g]))
Composable
=> (defrecord Comp [fs]
clojure.lang.IFn
(invoke [_ x]
(reduce (fn [x f] (f x)) x (rseq fs)))
Composable
(compj [f g] (Comp. (conj fs g))))
cljug.core.Comp
=> (extend-protocol Composable
Object
(compj [f g]
(Comp. [f g])))
nil
=> (compj (compj inc #(* 2 %)) dec)
#cljug.core.Comp{:fs [#<core$inc clojure.core$inc@59fdd712> #<core$eval4305$fn__4306 cljug.core$eval4305$fn__4306@2f93e4a8> #<core$dec clojure.core$dec@76ba6fe7>]}
=> (declare ->EvenComp ->OddComp)
#'cljug.core/->OddComp
=> (defrecord EvenComp [f]
clojure.lang.IFn
(invoke [_ x]
(f x))
Composable
(compj [_ g] (->OddComp f g)))
cljug.core.EvenComp
=> (defrecord OddComp [f g]
clojure.lang.IFn
(invoke [_ x]
(f (g x)))
Composable
(compj [_ h] (->EvenComp (compj f #(g (h %))))))
cljug.core.OddComp
=> (extend-protocol Composable
Object
(compj [f g]
(compj (->EvenComp f) g)))
nil
=> (compj (compj inc #(* 2 %)) dec)
#cljug.core.EvenComp{:f #cljug.core.OddComp{:f #<core$inc clojure.core$inc@59fdd712>, :g #<OddComp$fn__4506 cljug.core.OddComp$fn__4506@3815ac99>}}
=> (*1 10)
19
=> (extend-protocol Composable
Object
(compj [f g]
(->OddComp f g)))
nil
=> (defrecord OddComp [f g]
clojure.lang.IFn
(invoke [_ x]
(f (g x)))
Composable
(compj [_ h] (compj f #(g (h %)))))
cljug.core.OddComp
=> ;; plus besoin de EvenComp
=> (compj (compj inc #(* 2 %)) dec)
#cljug.core.OddComp{:f #<core$inc clojure.core$inc@59fdd712>, :g #<OddComp$fn__4587 cljug.core.OddComp$fn__4587@2b4d2239>}
=> (*1 10)
19
=> (compj (compj (compj inc #(* 2 %)) dec) identity)
#cljug.core.OddComp{:f #<core$inc clojure.core$inc@59fdd712>, :g #<OddComp$fn__4587 cljug.core.OddComp$fn__4587@6b61c3a0>}
=> (compj (compj (compj inc #(* 2 %)) dec) #(* 3))
#cljug.core.OddComp{:f #<core$inc clojure.core$inc@59fdd712>, :g #<OddComp$fn__4587 cljug.core.OddComp$fn__4587@2aee41aa>}
=> (*1 10)
ArityException Wrong number of args (1) passed to: core$eval4638$fn clojure.lang.AFn.throwArity (AFn.java:437)
=> (compj (compj (compj inc #(* 2 %)) dec) #(* 3 %))
#cljug.core.OddComp{:f #<core$inc clojure.core$inc@59fdd712>, :g #<OddComp$fn__4587 cljug.core.OddComp$fn__4587@56d3a88f>}
=> (*1 10)
59
=> ;; et on peut appliquer la même technique (pair/impair, cf okasaki) pour réimplémenter fcons e manière arborescente
=> ;; exercice laissé à la charge du lecteur :-)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment