Skip to content

Commit 0bfb38b

Browse files
authored
Merge pull request #16 from kaaninho/plain-lens-functions
Make plain lenses into variadic functions by removing the Lens protocol
2 parents 5ac85a4 + 6b36871 commit 0bfb38b

File tree

2 files changed

+28
-32
lines changed

2 files changed

+28
-32
lines changed

src/active/clojure/lens.cljc

Lines changed: 10 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,37 @@
11
(ns active.clojure.lens)
22

3-
(defprotocol Lens
4-
"Protocol for types that can be used as a lens, defined by a
5-
function to yank some value out of a given data value, and a function
6-
to shove an updated value back in."
7-
(-yank [lens data])
8-
(-shove [lens data v]))
9-
103
;; TODO document lens laws
114

125
(defn yank
136
"Yank a value from the given data value, as defined by the given
147
lens."
158
[data lens]
16-
(-yank lens data))
9+
(lens data))
1710

1811
(defn shove
1912
"Shove a new value v into the given data value, as defined by the
2013
given lens, and return the updated data structure."
2114
[data lens v]
22-
(-shove lens data v))
23-
24-
;; Keywords are lenses over a map (or object), focusing on the value associated with that keyword.
25-
(extend-type #?(:clj clojure.lang.Keyword) #?(:cljs cljs.core.Keyword)
26-
Lens
27-
(-yank [kw data] (kw data))
28-
(-shove [kw data v] (assoc data kw v)))
15+
(if (keyword? lens)
16+
(assoc data lens v)
17+
(lens data v)))
2918

3019
(defrecord ExplicitLens
3120
^{:private true}
3221
[yanker shover args]
33-
Lens
34-
(-yank [lens data] (apply yanker data args))
35-
(-shove [lens data v] (apply shover data v args))
3622
#?@(:clj [clojure.lang.IFn
37-
(invoke [this data] (-yank this data))
38-
(invoke [this data v] (-shove this data v))
23+
(invoke [this data] (apply yanker data args))
24+
(invoke [this data v] (apply shover data v args))
3925
(applyTo [this args]
4026
(let [args (object-array args)]
4127
(case (count args)
42-
1 (-yank this (aget args 0))
43-
2 (-shove this (aget args 0) (aget args 1))
28+
1 (yanker (aget args 0))
29+
2 (shover (aget args 0) (aget args 1))
4430
(throw #?(:clj (java.lang.IllegalArgumentException. (str "invalid number of arguments (" (count args) ") to lens")))
4531
#?(:cljs (str "invalid number of arguments (" (count args) ") to lens"))))))]
4632
:cljs [IFn
47-
(-invoke [this data] (-yank this data))
48-
(-invoke [this data v] (-shove this data v))]))
33+
(-invoke [this data] (apply yanker data args))
34+
(-invoke [this data v] (apply shover data v args))]))
4935

5036
(defn lens
5137
"Returns a new lens defined by the given yanker function, which
@@ -95,7 +81,6 @@
9581
value of the last one, in a data structure that the first one is put
9682
over."
9783
[l1 & lmore]
98-
(assert (not-any? #(not (satisfies? Lens %)) (cons l1 lmore)))
9984
(loop [res l1
10085
lmore lmore]
10186
(if (empty? lmore)

test/active/clojure/lens_test.cljc

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -248,10 +248,21 @@
248248
(lens/shove 'baz lens/id 'bar))))
249249

250250

251-
(deftest fct
252-
(is (= 1
253-
(lens/nel-head [1 2 3 4])))
254-
(is (= [5 2 3 4]
255-
(lens/nel-head [1 2 3 4] 5)))
256-
(is (= [5 2 3 4]
257-
(apply lens/nel-head [1 2 3 4] [5]))))
251+
(deftest explicit-lens-invocation
252+
(testing "can use explicit lens like a function, for yank"
253+
(is (= 1
254+
(lens/nel-head [1 2 3 4])))
255+
(is (= 4
256+
((lens/pos 3) [1 2 3 4]))))
257+
(testing "can use explicit lens like a function, for shove"
258+
(is (= [5 2 3 4]
259+
(lens/nel-head [1 2 3 4] 5)))
260+
(is (= [1 2 3 5]
261+
((lens/pos 3) [1 2 3 4] 5))))
262+
(testing "can apply explicit lens"
263+
(is (= [5 2 3 4]
264+
(apply lens/nel-head [1 2 3 4] [5])))))
265+
266+
(deftest lens-composition-equality
267+
(is (= (lens/>> (lens/pos 3) lens/nel-head)
268+
(lens/>> (lens/pos 3) lens/nel-head))))

0 commit comments

Comments
 (0)