22
33import com .jnape .palatable .lambda .adt .Maybe ;
44import com .jnape .palatable .lambda .adt .hlist .Tuple2 ;
5+ import com .jnape .palatable .lambda .functions .Fn1 ;
56import com .jnape .palatable .lambda .functions .builtin .fn2 .Filter ;
7+ import com .jnape .palatable .lambda .io .IO ;
68import com .jnape .palatable .lambda .lens .Iso ;
79import com .jnape .palatable .lambda .lens .Lens ;
810
1214import java .util .HashSet ;
1315import java .util .Map ;
1416import java .util .Set ;
17+ import java .util .function .Function ;
1518
1619import static com .jnape .palatable .lambda .adt .Maybe .maybe ;
20+ import static com .jnape .palatable .lambda .functions .builtin .fn2 .Alter .alter ;
1721import static com .jnape .palatable .lambda .functions .builtin .fn2 .Map .map ;
1822import static com .jnape .palatable .lambda .functions .builtin .fn2 .ToCollection .toCollection ;
1923import static com .jnape .palatable .lambda .functions .builtin .fn2 .ToMap .toMap ;
2024import static com .jnape .palatable .lambda .lens .Lens .Simple .adapt ;
25+ import static com .jnape .palatable .lambda .lens .Lens .lens ;
2126import static com .jnape .palatable .lambda .lens .Lens .simpleLens ;
2227import static com .jnape .palatable .lambda .lens .functions .View .view ;
2328import static com .jnape .palatable .lambda .lens .lenses .MaybeLens .unLiftA ;
@@ -31,6 +36,20 @@ public final class MapLens {
3136 private MapLens () {
3237 }
3338
39+ /**
40+ * A lens that focuses on a copy of a {@link Map} as a subtype <code>M</code>. Useful for composition to avoid
41+ * mutating a map reference.
42+ *
43+ * @param <M> the map subtype
44+ * @param <K> the key type
45+ * @param <V> the value type
46+ * @return a lens that focuses on copies of maps as a specific subtype
47+ */
48+ public static <M extends Map <K , V >, K , V > Lens <Map <K , V >, M , M , M > asCopy (
49+ Function <? super Map <K , V >, ? extends M > copyFn ) {
50+ return lens (copyFn , (__ , copy ) -> copy );
51+ }
52+
3453 /**
3554 * A lens that focuses on a copy of a Map. Useful for composition to avoid mutating a map reference.
3655 *
@@ -39,7 +58,26 @@ private MapLens() {
3958 * @return a lens that focuses on copies of maps
4059 */
4160 public static <K , V > Lens .Simple <Map <K , V >, Map <K , V >> asCopy () {
42- return simpleLens (HashMap ::new , (__ , copy ) -> copy );
61+ return adapt (asCopy (HashMap ::new ));
62+ }
63+
64+ /**
65+ * A lens that focuses on a value at a key in a map, as a {@link Maybe}, and produces a subtype <code>M</code> on
66+ * the way back out.
67+ *
68+ * @param <M> the map subtype
69+ * @param <K> the key type
70+ * @param <V> the value type
71+ * @param k the key to focus on
72+ * @return a lens that focuses on the value at key, as a {@link Maybe}
73+ */
74+ public static <M extends Map <K , V >, K , V > Lens <Map <K , V >, M , Maybe <V >, Maybe <V >> valueAt (
75+ Function <? super Map <K , V >, ? extends M > copyFn , K k ) {
76+ return lens (m -> maybe (m .get (k )), (m , maybeV ) -> maybeV
77+ .<Fn1 <M , IO <M >>>fmap (v -> alter (updated -> updated .put (k , v )))
78+ .orElse (alter (updated -> updated .remove (k )))
79+ .apply (copyFn .apply (m ))
80+ .unsafePerformIO ());
4381 }
4482
4583 /**
@@ -51,16 +89,7 @@ public static <K, V> Lens.Simple<Map<K, V>, Map<K, V>> asCopy() {
5189 * @return a lens that focuses on the value at key, as a {@link Maybe}
5290 */
5391 public static <K , V > Lens .Simple <Map <K , V >, Maybe <V >> valueAt (K k ) {
54- return simpleLens (m -> maybe (m .get (k )), (m , maybeV ) -> {
55- Map <K , V > updated = new HashMap <>(m );
56- return maybeV .fmap (v -> {
57- updated .put (k , v );
58- return updated ;
59- }).orElseGet (() -> {
60- updated .remove (k );
61- return updated ;
62- });
63- });
92+ return adapt (valueAt (HashMap ::new , k ));
6493 }
6594
6695 /**
@@ -75,7 +104,6 @@ public static <K, V> Lens.Simple<Map<K, V>, Maybe<V>> valueAt(K k) {
75104 * @param <V> the value type
76105 * @return a lens that focuses on the value at the key
77106 */
78- @ SuppressWarnings ("unchecked" )
79107 public static <K , V > Lens .Simple <Map <K , V >, V > valueAt (K k , V defaultValue ) {
80108 return adapt (unLiftB (unLiftA (valueAt (k ), defaultValue )));
81109 }
@@ -150,8 +178,7 @@ public static <K, V> Lens.Simple<Map<K, V>, Map<V, K>> inverted() {
150178 /**
151179 * A lens that focuses on a map while mapping its values with the mapping {@link Iso}.
152180 * <p>
153- * Note that for this lens to be lawful, <code>iso</code> must be bijective: that is, every <code>V</code> must
154- * uniquely and invertibly map to exactly one <code>V2</code>.
181+ * Note that for this lens to be lawful, <code>iso</code> must be lawful.
155182 *
156183 * @param iso the mapping {@link Iso}
157184 * @param <K> the key type
0 commit comments