11package com .jnape .palatable .lambda .optics ;
22
3+ import com .jnape .palatable .lambda .functions .Fn1 ;
34import com .jnape .palatable .lambda .functions .specialized .Pure ;
45import com .jnape .palatable .lambda .functor .Applicative ;
56import com .jnape .palatable .lambda .functor .Functor ;
67import com .jnape .palatable .lambda .functor .Profunctor ;
78import com .jnape .palatable .lambda .functor .builtin .Identity ;
89
10+ import static com .jnape .palatable .lambda .optics .Optic .reframe ;
11+
912/**
1013 * A generic supertype representation for a profunctor {@link Optic} that requires a {@link Pure} implementation to
11- * derive its {@link Functor} constraint and graduate to a full-fledge {@link Optic}.
14+ * derive its {@link Functor} constraint and graduate to a full-fledge {@link Optic}, equipped with a default
15+ * {@link Optic} instance for the profunctor constraint and {@link Identity}.
1216 *
1317 * @param <P> the {@link Profunctor} bound
1418 * @param <S> the left side of the output profunctor
@@ -30,11 +34,102 @@ public interface ProtoOptic<P extends Profunctor<?, ?, ? extends P>, S, T, A, B>
3034 */
3135 <F extends Applicative <?, F >> Optic <P , F , S , T , A , B > toOptic (Pure <F > pure );
3236
37+ /**
38+ * {@inheritDoc}
39+ */
3340 @ Override
3441 default <CoP extends Profunctor <?, ?, ? extends P >, CoF extends Functor <?, ? extends Identity <?>>,
3542 FB extends Functor <B , ? extends CoF >, FT extends Functor <T , ? extends CoF >,
3643 PAFB extends Profunctor <A , FB , ? extends CoP >,
3744 PSFT extends Profunctor <S , FT , ? extends CoP >> PSFT apply (PAFB pafb ) {
3845 return toOptic (Pure .<Identity <?>>pure (Identity ::new )).apply (pafb );
3946 }
47+
48+ /**
49+ * Left-to-right composition of proto-optics. Requires compatibility between <code>S</code> and <code>T</code>.
50+ *
51+ * @param f the other proto-optic
52+ * @param <Z> the new left side of the input profunctor
53+ * @param <C> the new right side's functor embedding of the input profunctor
54+ * @return the composed proto-optic
55+ */
56+ default <Z , C > ProtoOptic <P , S , T , Z , C > andThen (ProtoOptic <? super P , A , B , Z , C > f ) {
57+ return new ProtoOptic <P , S , T , Z , C >() {
58+ @ Override
59+ public <F extends Applicative <?, F >> Optic <P , F , S , T , Z , C > toOptic (Pure <F > pure ) {
60+ Optic <? super P , F , A , B , Z , C > optic = f .toOptic (pure );
61+ return ProtoOptic .this .toOptic (pure ).andThen (reframe (optic ));
62+ }
63+ };
64+ }
65+
66+ /**
67+ * Right-to-Left composition of proto-optics. Requires compatibility between <code>A</code> and <code>B</code>.
68+ *
69+ * @param g the other proto-optic
70+ * @param <R> the new left side of the output profunctor
71+ * @param <U> the new right side's functor embedding of the output profunctor
72+ * @return the composed proto-optic
73+ */
74+ default <R , U > ProtoOptic <P , R , U , A , B > compose (ProtoOptic <? super P , R , U , S , T > g ) {
75+ return new ProtoOptic <P , R , U , A , B >() {
76+ @ Override
77+ public <F extends Applicative <?, F >> Optic <P , F , R , U , A , B > toOptic (Pure <F > pure ) {
78+ Optic <? super P , F , R , U , S , T > optic = g .toOptic (pure );
79+ return ProtoOptic .this .toOptic (pure ).compose (reframe (optic ));
80+ }
81+ };
82+ }
83+
84+ /**
85+ * {@inheritDoc}
86+ */
87+ @ Override
88+ default <R > ProtoOptic <P , R , T , A , B > mapS (Fn1 <? super R , ? extends S > fn ) {
89+ return new ProtoOptic <P , R , T , A , B >() {
90+ @ Override
91+ public <F extends Applicative <?, F >> Optic <P , F , R , T , A , B > toOptic (Pure <F > pure ) {
92+ return ProtoOptic .this .toOptic (pure ).mapS (fn );
93+ }
94+ };
95+ }
96+
97+ /**
98+ * {@inheritDoc}
99+ */
100+ @ Override
101+ default <U > ProtoOptic <P , S , U , A , B > mapT (Fn1 <? super T , ? extends U > fn ) {
102+ return new ProtoOptic <P , S , U , A , B >() {
103+ @ Override
104+ public <F extends Applicative <?, F >> Optic <P , F , S , U , A , B > toOptic (Pure <F > pure ) {
105+ return ProtoOptic .this .toOptic (pure ).mapT (fn );
106+ }
107+ };
108+ }
109+
110+ /**
111+ * {@inheritDoc}
112+ */
113+ @ Override
114+ default <C > ProtoOptic <P , S , T , C , B > mapA (Fn1 <? super A , ? extends C > fn ) {
115+ return new ProtoOptic <P , S , T , C , B >() {
116+ @ Override
117+ public <F extends Applicative <?, F >> Optic <P , F , S , T , C , B > toOptic (Pure <F > pure ) {
118+ return ProtoOptic .this .toOptic (pure ).mapA (fn );
119+ }
120+ };
121+ }
122+
123+ /**
124+ * {@inheritDoc}
125+ */
126+ @ Override
127+ default <Z > ProtoOptic <P , S , T , A , Z > mapB (Fn1 <? super Z , ? extends B > fn ) {
128+ return new ProtoOptic <P , S , T , A , Z >() {
129+ @ Override
130+ public <F extends Applicative <?, F >> Optic <P , F , S , T , A , Z > toOptic (Pure <F > pure ) {
131+ return ProtoOptic .this .toOptic (pure ).mapB (fn );
132+ }
133+ };
134+ }
40135}
0 commit comments