|
1 | 1 | (ns active.clojure.lens)
|
2 | 2 |
|
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 |
| - |
10 | 3 | ;; TODO document lens laws
|
11 | 4 |
|
12 | 5 | (defn yank
|
13 | 6 | "Yank a value from the given data value, as defined by the given
|
14 | 7 | lens."
|
15 | 8 | [data lens]
|
16 |
| - (-yank lens data)) |
| 9 | + (lens data)) |
17 | 10 |
|
18 | 11 | (defn shove
|
19 | 12 | "Shove a new value v into the given data value, as defined by the
|
20 | 13 | given lens, and return the updated data structure."
|
21 | 14 | [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))) |
29 | 18 |
|
30 | 19 | (defrecord ExplicitLens
|
31 | 20 | ^{:private true}
|
32 | 21 | [yanker shover args]
|
33 |
| - Lens |
34 |
| - (-yank [lens data] (apply yanker data args)) |
35 |
| - (-shove [lens data v] (apply shover data v args)) |
36 | 22 | #?@(: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)) |
39 | 25 | (applyTo [this args]
|
40 | 26 | (let [args (object-array args)]
|
41 | 27 | (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)) |
44 | 30 | (throw #?(:clj (java.lang.IllegalArgumentException. (str "invalid number of arguments (" (count args) ") to lens")))
|
45 | 31 | #?(:cljs (str "invalid number of arguments (" (count args) ") to lens"))))))]
|
46 | 32 | :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))])) |
49 | 35 |
|
50 | 36 | (defn lens
|
51 | 37 | "Returns a new lens defined by the given yanker function, which
|
|
95 | 81 | value of the last one, in a data structure that the first one is put
|
96 | 82 | over."
|
97 | 83 | [l1 & lmore]
|
98 |
| - (assert (not-any? #(not (satisfies? Lens %)) (cons l1 lmore))) |
99 | 84 | (loop [res l1
|
100 | 85 | lmore lmore]
|
101 | 86 | (if (empty? lmore)
|
|
0 commit comments