1+ package com .jnape .palatable .lambda .lens ;
2+
3+ import com .jnape .palatable .lambda .adt .hlist .Tuple2 ;
4+ import com .jnape .palatable .lambda .functions .Fn1 ;
5+ import com .jnape .palatable .lambda .functions .Fn2 ;
6+ import com .jnape .palatable .lambda .functor .Applicative ;
7+ import com .jnape .palatable .lambda .functor .Functor ;
8+ import com .jnape .palatable .lambda .functor .Profunctor ;
9+ import com .jnape .palatable .lambda .functor .builtin .Exchange ;
10+ import com .jnape .palatable .lambda .functor .builtin .Identity ;
11+ import com .jnape .palatable .lambda .lens .functions .Over ;
12+ import com .jnape .palatable .lambda .lens .functions .Set ;
13+ import com .jnape .palatable .lambda .lens .functions .View ;
14+ import com .jnape .palatable .lambda .monad .Monad ;
15+
16+ import java .util .function .Function ;
17+
18+ import static com .jnape .palatable .lambda .functions .Fn1 .fn1 ;
19+ import static com .jnape .palatable .lambda .functions .builtin .fn1 .Constantly .constantly ;
20+ import static com .jnape .palatable .lambda .functions .builtin .fn1 .Id .id ;
21+ import static com .jnape .palatable .lambda .lens .Iso .Simple .adapt ;
22+ import static com .jnape .palatable .lambda .lens .functions .View .view ;
23+
24+ /**
25+ * An {@link Iso} (short for "isomorphism") is an invertible {@link Lens}: a {@link LensLike} encoding of a
26+ * bi-directional focusing of two types, and like <code>{@link Lens}es</code>, can be <code>{@link View}ed</code>,
27+ * {@link Set}, and <code>{@link Over}ed</code>.
28+ * <p>
29+ * As an example, consider the isomorphism between valid {@link String}s and {@link Integer}s:
30+ * <pre>
31+ * {@code
32+ * Iso<String, String, Integer, Integer> stringIntIso = Iso.iso(Integer::parseInt, Object::toString);
33+ * Integer asInt = view(stringIntIso, "123"); // 123
34+ * String asString = view(stringIntIso.mirror(), 123); // "123"
35+ * }
36+ * </pre>
37+ * In the previous example, <code>stringIntIso</code> can be viewed as a <code>{@link Lens}<String, String, Integer,
38+ * Integer></code>, and can be <code>{@link Iso#mirror}ed</code> and viewed as a <code>{@link Lens}<Integer,
39+ * Integer, String, String></code>.
40+ * <p>
41+ * As with {@link Lens}, variance is supported between <code>S/T</code> and <code>A/B</code>, and where these pairs do
42+ * not vary, a {@link Simple} iso can be used (for instance, in the previous example, <code>stringIntIso</code> could
43+ * have had the simplified <code>Iso.Simple<String, Integer></code> type).
44+ * <p>
45+ * For more information, read about <a href="https://hackage.haskell.org/package/lens-4.16.1/docs/Control-Lens-Iso.html">isos</a>.
46+ *
47+ * @param <S> the larger type for focusing
48+ * @param <T> the larger type for mirrored focusing
49+ * @param <A> the smaller type for focusing
50+ * @param <B> the smaller type for mirrored focusing
51+ */
52+ @ FunctionalInterface
53+ public interface Iso <S , T , A , B > extends LensLike <S , T , A , B , Iso > {
54+
55+ <P extends Profunctor , F extends Functor , FB extends Functor <B , F >, FT extends Functor <T , F >,
56+ PAFB extends Profunctor <A , FB , P >,
57+ PSFT extends Profunctor <S , FT , P >> PSFT apply (PAFB pafb );
58+
59+ @ Override
60+ default <F extends Functor , FT extends Functor <T , F >, FB extends Functor <B , F >> FT apply (
61+ Function <? super A , ? extends FB > fn , S s ) {
62+ return this .<Fn1 , F , FB , FT , Fn1 <A , FB >, Fn1 <S , FT >>apply (fn1 (fn )).apply (s );
63+ }
64+
65+ /**
66+ * Convert this {@link Iso} into a {@link Lens}.
67+ *
68+ * @return the equivalent lens
69+ */
70+ default Lens <S , T , A , B > toLens () {
71+ return new Lens <S , T , A , B >() {
72+ @ Override
73+ public <F extends Functor , FT extends Functor <T , F >, FB extends Functor <B , F >> FT apply (
74+ Function <? super A , ? extends FB > fn , S s ) {
75+ return Iso .this .apply (fn1 (fn ), s );
76+ }
77+ };
78+ }
79+
80+ /**
81+ * Flip this {@link Iso} around.
82+ *
83+ * @return the mirrored {@link Iso}
84+ */
85+ default Iso <B , A , T , S > mirror () {
86+ return unIso ().into ((sa , bt ) -> iso (bt , sa ));
87+ }
88+
89+ /**
90+ * Destructure this {@link Iso} into the two functions <code>S -< A</code> and <code>B -< T</code> that
91+ * constitute the isomorphism.
92+ *
93+ * @return the destructured iso
94+ */
95+ default Tuple2 <? extends Function <? super S , ? extends A >, ? extends Function <? super B , ? extends T >> unIso () {
96+ return Tuple2 .fill (this .<Exchange <A , B , ?, ?>, Identity , Identity <B >, Identity <T >,
97+ Exchange <A , B , A , Identity <B >>,
98+ Exchange <A , B , S , Identity <T >>>apply (new Exchange <>(id (), Identity ::new )).diMapR (Identity ::runIdentity ))
99+ .biMap (Exchange ::sa , Exchange ::bt );
100+ }
101+
102+ @ Override
103+ default <U > Iso <S , U , A , B > fmap (Function <? super T , ? extends U > fn ) {
104+ return LensLike .super .<U >fmap (fn ).coerce ();
105+ }
106+
107+ @ Override
108+ default <U > Iso <S , U , A , B > pure (U u ) {
109+ return iso (view (this ), constantly (u ));
110+ }
111+
112+ @ Override
113+ default <U > Iso <S , U , A , B > zip (Applicative <Function <? super T , ? extends U >, LensLike <S , ?, A , B , Iso >> appFn ) {
114+ return LensLike .super .zip (appFn ).coerce ();
115+ }
116+
117+ @ Override
118+ default <U > Iso <S , U , A , B > discardL (Applicative <U , LensLike <S , ?, A , B , Iso >> appB ) {
119+ return LensLike .super .discardL (appB ).coerce ();
120+ }
121+
122+ @ Override
123+ default <U > Iso <S , T , A , B > discardR (Applicative <U , LensLike <S , ?, A , B , Iso >> appB ) {
124+ return LensLike .super .discardR (appB ).coerce ();
125+ }
126+
127+ @ Override
128+ default <U > Iso <S , U , A , B > flatMap (Function <? super T , ? extends Monad <U , LensLike <S , ?, A , B , Iso >>> fn ) {
129+ return unIso ().fmap (bt -> Fn2 .<B , B , U >fn2 (fn1 (bt .andThen (fn .<Iso <S , U , A , B >>andThen (Applicative ::coerce ))
130+ .andThen (Iso ::unIso )
131+ .andThen (Tuple2 ::_2 )
132+ .andThen (Fn1 ::fn1 ))))
133+ .fmap (Fn2 ::uncurry )
134+ .fmap (bbu -> bbu .<B >diMapL (Tuple2 ::fill ))
135+ .into (Iso ::iso );
136+ }
137+
138+ @ Override
139+ default <R > Iso <R , T , A , B > diMapL (Function <? super R , ? extends S > fn ) {
140+ return LensLike .super .<R >diMapL (fn ).coerce ();
141+ }
142+
143+ @ Override
144+ default <U > Iso <S , U , A , B > diMapR (Function <? super T , ? extends U > fn ) {
145+ return LensLike .super .<U >diMapR (fn ).coerce ();
146+ }
147+
148+ @ Override
149+ default <R , U > Iso <R , U , A , B > diMap (Function <? super R , ? extends S > lFn ,
150+ Function <? super T , ? extends U > rFn ) {
151+ return LensLike .super .<R , U >diMap (lFn , rFn ).coerce ();
152+ }
153+
154+ @ Override
155+ default <R > Iso <R , T , A , B > contraMap (Function <? super R , ? extends S > fn ) {
156+ return LensLike .super .<R >contraMap (fn ).coerce ();
157+ }
158+
159+ @ Override
160+ default <R > Iso <R , T , A , B > mapS (Function <? super R , ? extends S > fn ) {
161+ return unIso ().biMapL (f -> f .compose (fn )).into (Iso ::iso );
162+ }
163+
164+ @ Override
165+ default <U > Iso <S , U , A , B > mapT (Function <? super T , ? extends U > fn ) {
166+ return unIso ().biMapR (f -> f .andThen (fn )).into (Iso ::iso );
167+ }
168+
169+ @ Override
170+ default <C > Iso <S , T , C , B > mapA (Function <? super A , ? extends C > fn ) {
171+ return unIso ().biMapL (f -> f .andThen (fn )).into (Iso ::iso );
172+ }
173+
174+ @ Override
175+ default <Z > Iso <S , T , A , Z > mapB (Function <? super Z , ? extends B > fn ) {
176+ return unIso ().biMapR (f -> f .compose (fn )).into (Iso ::iso );
177+ }
178+
179+ /**
180+ * Left-to-right composition of {@link Iso}.
181+ *
182+ * @param f the iso to apply after this one
183+ * @param <C> the smaller type the first larger type can be viewed as
184+ * @param <D> the smaller type that can be viewed as the second larger type
185+ * @return the composed {@link Iso}
186+ */
187+ default <C , D > Iso <S , T , C , D > andThen (Iso <A , B , C , D > f ) {
188+ return unIso ().into ((sa , bt ) -> f .unIso ().into ((ac , db ) -> iso (sa .andThen (ac ), db .andThen (bt ))));
189+ }
190+
191+ /**
192+ * Right-to-left composition of {@link Iso}.
193+ *
194+ * @param g the iso to apply before this one
195+ * @param <Q> the larger type that can be viewed as the first smaller type
196+ * @param <R> the larger type the second smaller type can be viewed as
197+ * @return the composed {@link Iso}
198+ */
199+ default <Q , R > Iso <Q , R , A , B > compose (Iso <Q , R , S , T > g ) {
200+ return g .andThen (this );
201+ }
202+
203+ /**
204+ * Static factory method for creating an iso from a function and it's inverse.
205+ *
206+ * @param f the function
207+ * @param g f's inverse
208+ * @param <S> the larger type for focusing
209+ * @param <T> the larger type for mirrored focusing
210+ * @param <A> the smaller type for focusing
211+ * @param <B> the smaller type for mirrored focusing
212+ * @return the iso
213+ */
214+ static <S , T , A , B > Iso <S , T , A , B > iso (Function <? super S , ? extends A > f ,
215+ Function <? super B , ? extends T > g ) {
216+ return new Iso <S , T , A , B >() {
217+ @ Override
218+ @ SuppressWarnings ("unchecked" )
219+ public <P extends Profunctor , F extends Functor , FB extends Functor <B , F >, FT extends Functor <T , F >, PAFB extends Profunctor <A , FB , P >, PSFT extends Profunctor <S , FT , P >> PSFT apply (
220+ PAFB pafb ) {
221+ return (PSFT ) pafb .<S , FT >diMap (f , fb -> (FT ) fb .<T >fmap (g ));
222+ }
223+ };
224+ }
225+
226+ /**
227+ * Static factory method for creating a simple {@link Iso} from a function and its inverse.
228+ *
229+ * @param f a function
230+ * @param g f's inverse
231+ * @param <S> one side of the isomorphism
232+ * @param <A> the other side of the isomorphism
233+ * @return the simple iso
234+ */
235+ static <S , A > Iso .Simple <S , A > simpleIso (Function <? super S , ? extends A > f , Function <? super A , ? extends S > g ) {
236+ return adapt (iso (f , g ));
237+ }
238+
239+ /**
240+ * A convenience type with a simplified type signature for common isos with both unified "larger" values and
241+ * unified "smaller" values.
242+ *
243+ * @param <S> the type of both "larger" values
244+ * @param <A> the type of both "smaller" values
245+ */
246+ interface Simple <S , A > extends Iso <S , S , A , A >, LensLike .Simple <S , A , Iso > {
247+
248+ @ Override
249+ default Iso .Simple <A , S > mirror () {
250+ return Iso .Simple .adapt (Iso .super .mirror ());
251+ }
252+
253+ @ Override
254+ default Lens .Simple <S , A > toLens () {
255+ return Lens .Simple .adapt (Iso .super .toLens ());
256+ }
257+
258+ /**
259+ * Compose two simple isos from right to left.
260+ *
261+ * @param g the other simple iso
262+ * @param <R> the other simple iso' larger type
263+ * @return the composed simple iso
264+ */
265+ default <R > Iso .Simple <R , A > compose (Iso .Simple <R , S > g ) {
266+ return g .andThen (this );
267+ }
268+
269+ /**
270+ * Compose two simple isos from left to right.
271+ *
272+ * @param f the other simple iso
273+ * @param <B> the other simple iso' smaller type
274+ * @return the composed simple iso
275+ */
276+ default <B > Iso .Simple <S , B > andThen (Iso .Simple <A , B > f ) {
277+ return Iso .Simple .adapt (f .compose (this ));
278+ }
279+
280+ /**
281+ * Adapt an {@link Iso} with the right variance to an {@link Iso.Simple}.
282+ *
283+ * @param iso the iso
284+ * @param <S> S/T
285+ * @param <A> A/B
286+ * @return the simple iso
287+ */
288+ @ SuppressWarnings ("unchecked" )
289+ static <S , A > Iso .Simple <S , A > adapt (Iso <S , S , A , A > iso ) {
290+ return iso ::apply ;
291+ }
292+ }
293+ }
0 commit comments