Skip to content

Commit f2ce481

Browse files
committed
MonadT is now witnessed for better subtyping compatibility
1 parent 19cd301 commit f2ce481

8 files changed

Lines changed: 64 additions & 68 deletions

File tree

src/main/java/com/jnape/palatable/lambda/monad/transformer/MonadT.java

Lines changed: 27 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,26 @@
22

33
import com.jnape.palatable.lambda.functions.Fn1;
44
import com.jnape.palatable.lambda.functor.Applicative;
5+
import com.jnape.palatable.lambda.functor.Functor;
56
import com.jnape.palatable.lambda.functor.builtin.Lazy;
67
import com.jnape.palatable.lambda.monad.Monad;
8+
import com.jnape.palatable.lambda.monad.transformer.builtin.EitherT;
79
import com.jnape.palatable.lambda.monad.transformer.builtin.MaybeT;
10+
import com.jnape.palatable.lambda.monad.transformer.builtin.ReaderT;
811

912
/**
10-
* An interface representing a {@link Monad} transformer.
13+
* While any two {@link Functor functors} and any two {@link Applicative applicatives} can be composed in general, the
14+
* same is not true in general of any two {@link Monad monads}, in general. However, there exist {@link Monad monads}
15+
* that do compose, in general, with any other {@link Monad}. When this is the case, the combination of these
16+
* {@link Monad monads} with any other {@link Monad} can offer implementations of {@link Monad#pure pure} and
17+
* {@link Monad#flatMap(Fn1) flatMap} for free, simply by relying on the other {@link Monad monad's} implementation of
18+
* both, as well as their own privileged knowledge about how to merge the nested {@link Monad#flatMap(Fn1) flatMap}
19+
* call. This can be thought of as "gluing" together two {@link Monad monads}, allowing easier access to their values,
20+
* as well as, in some cases, providing universally correct constructions of the composed short-circuiting algorithms.
1121
* <p>
12-
* While any two {@link com.jnape.palatable.lambda.functor.Functor functors} and any two
13-
* {@link Applicative applicatives} can be composed in general, the same is not true in general of any two
14-
* {@link Monad monads}. However, there exist {@link Monad monads} that do compose, in general, with any other
15-
* {@link Monad}, provided that they are embedded inside the other {@link Monad}. When this is the case, they can offer
16-
* implementations of {@link Monad#pure pure} and {@link Monad#flatMap(Fn1) flatMap} for free, simply by relying
17-
* on the outer {@link Monad monad's} implementation of both, as well as their own privileged knowledge about how to
18-
* merge the nested {@link Monad#flatMap(Fn1) flatMap} call.
19-
* <p>
20-
* The term "monad transformer" describes a particular encoding of monadic composition. Because this general composition
21-
* of a particular {@link Monad} with any other {@link Monad} relies on privileged knowledge about the embedded
22-
* {@link Monad}, the {@link MonadT transformer} representing this compositions is described from the embedded
23-
* {@link Monad monad's} perspective (e.g. {@link MaybeT} describing the embedding
24-
* <code>{@link Monad}&lt;{@link com.jnape.palatable.lambda.adt.Maybe}&lt;A&gt;&gt;</code>).
25-
* <p>
26-
* Additionally, monad transformers connected by compatible {@link Monad monads} also compose. When two or more monad
27-
* transformers are composed, this is generally referred to as a "monad transformer stack".
22+
* The term "monad transformer" describes this particular encoding of monadic composition, and tends to be
23+
* named in terms of {@link Monad} for which privileged knowledge must be known in order to eliminate during
24+
* {@link Monad#flatMap(Fn1) flatmapping}.
2825
* <p>
2926
* For more information, <a href="https://en.wikipedia.org/wiki/Monad_transformer" target="_blank">read more about</a>
3027
* monad transformers.
@@ -33,9 +30,11 @@
3330
* @param <G> the inner {@link Monad monad}
3431
* @param <A> the carrier type
3532
* @see MaybeT
33+
* @see EitherT
34+
* @see ReaderT
3635
*/
37-
public interface MonadT<F extends Monad<?, F>, G extends Monad<?, G>, A>
38-
extends Monad<A, MonadT<F, G, ?>> {
36+
public interface MonadT<F extends Monad<?, F>, G extends Monad<?, G>, A, MT extends MonadT<F, G, ?, MT>>
37+
extends Monad<A, MT> {
3938

4039
/**
4140
* Extract out the composed monad out of this transformer.
@@ -50,52 +49,52 @@ public interface MonadT<F extends Monad<?, F>, G extends Monad<?, G>, A>
5049
* {@inheritDoc}
5150
*/
5251
@Override
53-
<B> MonadT<F, G, B> flatMap(Fn1<? super A, ? extends Monad<B, MonadT<F, G, ?>>> f);
52+
<B> MonadT<F, G, B, MT> flatMap(Fn1<? super A, ? extends Monad<B, MT>> f);
5453

5554
/**
5655
* {@inheritDoc}
5756
*/
5857
@Override
59-
<B> MonadT<F, G, B> pure(B b);
58+
<B> MonadT<F, G, B, MT> pure(B b);
6059

6160
/**
6261
* {@inheritDoc}
6362
*/
6463
@Override
65-
default <B> MonadT<F, G, B> fmap(Fn1<? super A, ? extends B> fn) {
64+
default <B> MonadT<F, G, B, MT> fmap(Fn1<? super A, ? extends B> fn) {
6665
return Monad.super.<B>fmap(fn).coerce();
6766
}
6867

6968
/**
7069
* {@inheritDoc}
7170
*/
7271
@Override
73-
default <B> MonadT<F, G, B> zip(Applicative<Fn1<? super A, ? extends B>, MonadT<F, G, ?>> appFn) {
72+
default <B> MonadT<F, G, B, MT> zip(Applicative<Fn1<? super A, ? extends B>, MT> appFn) {
7473
return Monad.super.zip(appFn).coerce();
7574
}
7675

7776
/**
7877
* {@inheritDoc}
7978
*/
8079
@Override
81-
default <B> Lazy<? extends MonadT<F, G, B>> lazyZip(
82-
Lazy<? extends Applicative<Fn1<? super A, ? extends B>, MonadT<F, G, ?>>> lazyAppFn) {
83-
return Monad.super.lazyZip(lazyAppFn).fmap(Monad<B, MonadT<F, G, ?>>::coerce);
80+
default <B> Lazy<? extends MonadT<F, G, B, MT>> lazyZip(
81+
Lazy<? extends Applicative<Fn1<? super A, ? extends B>, MT>> lazyAppFn) {
82+
return Monad.super.lazyZip(lazyAppFn).fmap(Monad<B, MT>::coerce);
8483
}
8584

8685
/**
8786
* {@inheritDoc}
8887
*/
8988
@Override
90-
default <B> MonadT<F, G, B> discardL(Applicative<B, MonadT<F, G, ?>> appB) {
89+
default <B> MonadT<F, G, B, MT> discardL(Applicative<B, MT> appB) {
9190
return Monad.super.discardL(appB).coerce();
9291
}
9392

9493
/**
9594
* {@inheritDoc}
9695
*/
9796
@Override
98-
default <B> MonadT<F, G, A> discardR(Applicative<B, MonadT<F, G, ?>> appB) {
97+
default <B> MonadT<F, G, A, MT> discardR(Applicative<B, MT> appB) {
9998
return Monad.super.discardR(appB).coerce();
10099
}
101100
}

src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherT.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
*/
2424
public final class EitherT<M extends Monad<?, M>, L, R> implements
2525
Bifunctor<L, R, EitherT<M, ?, ?>>,
26-
MonadT<M, Either<L, ?>, R> {
26+
MonadT<M, Either<L, ?>, R, EitherT<M, L, ?>> {
2727

2828
private final Monad<Either<L, R>, M> melr;
2929

@@ -43,7 +43,7 @@ private EitherT(Monad<Either<L, R>, M> melr) {
4343
* {@inheritDoc}
4444
*/
4545
@Override
46-
public <R2> EitherT<M, L, R2> flatMap(Fn1<? super R, ? extends Monad<R2, MonadT<M, Either<L, ?>, ?>>> f) {
46+
public <R2> EitherT<M, L, R2> flatMap(Fn1<? super R, ? extends Monad<R2, EitherT<M, L, ?>>> f) {
4747
return eitherT(melr.flatMap(lr -> lr.match(l -> melr.pure(left(l)),
4848
r -> f.apply(r).<EitherT<M, L, R2>>coerce().run())));
4949
}
@@ -69,7 +69,7 @@ public <R2> EitherT<M, L, R2> fmap(Fn1<? super R, ? extends R2> fn) {
6969
*/
7070
@Override
7171
public <R2> EitherT<M, L, R2> zip(
72-
Applicative<Fn1<? super R, ? extends R2>, MonadT<M, Either<L, ?>, ?>> appFn) {
72+
Applicative<Fn1<? super R, ? extends R2>, EitherT<M, L, ?>> appFn) {
7373
return MonadT.super.zip(appFn).coerce();
7474
}
7575

@@ -78,7 +78,7 @@ public <R2> EitherT<M, L, R2> zip(
7878
*/
7979
@Override
8080
public <R2> Lazy<EitherT<M, L, R2>> lazyZip(
81-
Lazy<? extends Applicative<Fn1<? super R, ? extends R2>, MonadT<M, Either<L, ?>, ?>>> lazyAppFn) {
81+
Lazy<? extends Applicative<Fn1<? super R, ? extends R2>, EitherT<M, L, ?>>> lazyAppFn) {
8282
return new Compose<>(melr)
8383
.lazyZip(lazyAppFn.fmap(maybeT -> new Compose<>(
8484
maybeT.<EitherT<M, L, Fn1<? super R, ? extends R2>>>coerce()
@@ -91,15 +91,15 @@ public <R2> Lazy<EitherT<M, L, R2>> lazyZip(
9191
* {@inheritDoc}
9292
*/
9393
@Override
94-
public <R2> EitherT<M, L, R2> discardL(Applicative<R2, MonadT<M, Either<L, ?>, ?>> appB) {
94+
public <R2> EitherT<M, L, R2> discardL(Applicative<R2, EitherT<M, L, ?>> appB) {
9595
return MonadT.super.discardL(appB).coerce();
9696
}
9797

9898
/**
9999
* {@inheritDoc}
100100
*/
101101
@Override
102-
public <B> EitherT<M, L, R> discardR(Applicative<B, MonadT<M, Either<L, ?>, ?>> appB) {
102+
public <B> EitherT<M, L, R> discardR(Applicative<B, EitherT<M, L, ?>> appB) {
103103
return MonadT.super.discardR(appB).coerce();
104104
}
105105

src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityT.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
* @param <M> the outer {@link Monad}
1717
* @param <A> the carrier type
1818
*/
19-
public final class IdentityT<M extends Monad<?, M>, A> implements MonadT<M, Identity<?>, A> {
19+
public final class IdentityT<M extends Monad<?, M>, A> implements MonadT<M, Identity<?>, A, IdentityT<M, ?>> {
2020

2121
private final Monad<Identity<A>, M> mia;
2222

@@ -36,7 +36,7 @@ public <GA extends Monad<A, Identity<?>>, FGA extends Monad<GA, M>> FGA run() {
3636
* {@inheritDoc}
3737
*/
3838
@Override
39-
public <B> IdentityT<M, B> flatMap(Fn1<? super A, ? extends Monad<B, MonadT<M, Identity<?>, ?>>> f) {
39+
public <B> IdentityT<M, B> flatMap(Fn1<? super A, ? extends Monad<B, IdentityT<M, ?>>> f) {
4040
return identityT(mia.flatMap(identityA -> f.apply(identityA.runIdentity()).<IdentityT<M, B>>coerce().run()));
4141
}
4242

@@ -60,7 +60,7 @@ public <B> IdentityT<M, B> fmap(Fn1<? super A, ? extends B> fn) {
6060
* {@inheritDoc}
6161
*/
6262
@Override
63-
public <B> IdentityT<M, B> zip(Applicative<Fn1<? super A, ? extends B>, MonadT<M, Identity<?>, ?>> appFn) {
63+
public <B> IdentityT<M, B> zip(Applicative<Fn1<? super A, ? extends B>, IdentityT<M, ?>> appFn) {
6464
return MonadT.super.zip(appFn).coerce();
6565
}
6666

@@ -69,7 +69,7 @@ public <B> IdentityT<M, B> zip(Applicative<Fn1<? super A, ? extends B>, MonadT<M
6969
*/
7070
@Override
7171
public <B> Lazy<IdentityT<M, B>> lazyZip(
72-
Lazy<? extends Applicative<Fn1<? super A, ? extends B>, MonadT<M, Identity<?>, ?>>> lazyAppFn) {
72+
Lazy<? extends Applicative<Fn1<? super A, ? extends B>, IdentityT<M, ?>>> lazyAppFn) {
7373
return new Compose<>(mia)
7474
.lazyZip(lazyAppFn.fmap(maybeT -> new Compose<>(
7575
maybeT.<IdentityT<M, Fn1<? super A, ? extends B>>>coerce()
@@ -82,15 +82,15 @@ public <B> Lazy<IdentityT<M, B>> lazyZip(
8282
* {@inheritDoc}
8383
*/
8484
@Override
85-
public <B> IdentityT<M, B> discardL(Applicative<B, MonadT<M, Identity<?>, ?>> appB) {
85+
public <B> IdentityT<M, B> discardL(Applicative<B, IdentityT<M, ?>> appB) {
8686
return MonadT.super.discardL(appB).coerce();
8787
}
8888

8989
/**
9090
* {@inheritDoc}
9191
*/
9292
@Override
93-
public <B> IdentityT<M, A> discardR(Applicative<B, MonadT<M, Identity<?>, ?>> appB) {
93+
public <B> IdentityT<M, A> discardR(Applicative<B, IdentityT<M, ?>> appB) {
9494
return MonadT.super.discardR(appB).coerce();
9595
}
9696

src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyT.java

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
* @param <M> the outer {@link Monad}
1919
* @param <A> the carrier type
2020
*/
21-
public class LazyT<M extends Monad<?, M>, A> implements MonadT<M, Lazy<?>, A> {
21+
public class LazyT<M extends Monad<?, M>, A> implements MonadT<M, Lazy<?>, A, LazyT<M, ?>> {
2222

2323
private final Monad<Lazy<A>, M> mla;
2424

@@ -38,8 +38,9 @@ public <GA extends Monad<A, Lazy<?>>, FGA extends Monad<GA, M>> FGA run() {
3838
* {@inheritDoc}
3939
*/
4040
@Override
41-
public <B> LazyT<M, B> flatMap(Fn1<? super A, ? extends Monad<B, MonadT<M, Lazy<?>, ?>>> f) {
42-
return new LazyT<>(mla.flatMap(lazyA -> f.apply(lazyA.value()).<MonadT<M, Lazy<?>, B>>coerce().run()));
41+
public <B> LazyT<M, B> flatMap(Fn1<? super A, ? extends Monad<B, LazyT<M, ?>>> f) {
42+
return new LazyT<>(mla.flatMap(lazyA -> f.apply(lazyA.value())
43+
.<MonadT<M, Lazy<?>, B, LazyT<M, ?>>>coerce().run()));
4344
}
4445

4546
/**
@@ -62,7 +63,7 @@ public <B> LazyT<M, B> fmap(Fn1<? super A, ? extends B> fn) {
6263
* {@inheritDoc}
6364
*/
6465
@Override
65-
public <B> LazyT<M, B> zip(Applicative<Fn1<? super A, ? extends B>, MonadT<M, Lazy<?>, ?>> appFn) {
66+
public <B> LazyT<M, B> zip(Applicative<Fn1<? super A, ? extends B>, LazyT<M, ?>> appFn) {
6667
return MonadT.super.zip(appFn).coerce();
6768
}
6869

@@ -71,7 +72,7 @@ public <B> LazyT<M, B> zip(Applicative<Fn1<? super A, ? extends B>, MonadT<M, La
7172
*/
7273
@Override
7374
public <B> Lazy<LazyT<M, B>> lazyZip(
74-
Lazy<? extends Applicative<Fn1<? super A, ? extends B>, MonadT<M, Lazy<?>, ?>>> lazyAppFn) {
75+
Lazy<? extends Applicative<Fn1<? super A, ? extends B>, LazyT<M, ?>>> lazyAppFn) {
7576
return new Compose<>(mla)
7677
.lazyZip(lazyAppFn.fmap(lazyT -> new Compose<>(
7778
lazyT.<LazyT<M, Fn1<? super A, ? extends B>>>coerce()
@@ -84,15 +85,15 @@ public <B> Lazy<LazyT<M, B>> lazyZip(
8485
* {@inheritDoc}
8586
*/
8687
@Override
87-
public <B> LazyT<M, B> discardL(Applicative<B, MonadT<M, Lazy<?>, ?>> appB) {
88+
public <B> LazyT<M, B> discardL(Applicative<B, LazyT<M, ?>> appB) {
8889
return MonadT.super.discardL(appB).coerce();
8990
}
9091

9192
/**
9293
* {@inheritDoc}
9394
*/
9495
@Override
95-
public <B> LazyT<M, A> discardR(Applicative<B, MonadT<M, Lazy<?>, ?>> appB) {
96+
public <B> LazyT<M, A> discardR(Applicative<B, LazyT<M, ?>> appB) {
9697
return MonadT.super.discardR(appB).coerce();
9798
}
9899

src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
* @param <M> the outer {@link Monad}
2121
* @param <A> the carrier type
2222
*/
23-
public final class MaybeT<M extends Monad<?, M>, A> implements MonadT<M, Maybe<?>, A> {
23+
public final class MaybeT<M extends Monad<?, M>, A> implements MonadT<M, Maybe<?>, A, MaybeT<M, ?>> {
2424

2525
private final Monad<Maybe<A>, M> mma;
2626

@@ -56,7 +56,7 @@ public <B> MaybeT<M, B> pure(B b) {
5656
* {@inheritDoc}
5757
*/
5858
@Override
59-
public <B> MaybeT<M, B> zip(Applicative<Fn1<? super A, ? extends B>, MonadT<M, Maybe<?>, ?>> appFn) {
59+
public <B> MaybeT<M, B> zip(Applicative<Fn1<? super A, ? extends B>, MaybeT<M, ?>> appFn) {
6060
return MonadT.super.zip(appFn).coerce();
6161
}
6262

@@ -65,7 +65,7 @@ public <B> MaybeT<M, B> zip(Applicative<Fn1<? super A, ? extends B>, MonadT<M, M
6565
*/
6666
@Override
6767
public <B> Lazy<MaybeT<M, B>> lazyZip(
68-
Lazy<? extends Applicative<Fn1<? super A, ? extends B>, MonadT<M, Maybe<?>, ?>>> lazyAppFn) {
68+
Lazy<? extends Applicative<Fn1<? super A, ? extends B>, MaybeT<M, ?>>> lazyAppFn) {
6969
return new Compose<>(mma)
7070
.lazyZip(lazyAppFn.fmap(maybeT -> new Compose<>(
7171
maybeT.<MaybeT<M, Fn1<? super A, ? extends B>>>coerce()
@@ -77,7 +77,7 @@ public <B> Lazy<MaybeT<M, B>> lazyZip(
7777
* {@inheritDoc}
7878
*/
7979
@Override
80-
public <B> MaybeT<M, B> flatMap(Fn1<? super A, ? extends Monad<B, MonadT<M, Maybe<?>, ?>>> f) {
80+
public <B> MaybeT<M, B> flatMap(Fn1<? super A, ? extends Monad<B, MaybeT<M, ?>>> f) {
8181
return maybeT(mma.flatMap(ma -> ma
8282
.match(constantly(mma.pure(nothing())),
8383
a -> f.apply(a).<MaybeT<M, B>>coerce().run())));
@@ -87,15 +87,15 @@ public <B> MaybeT<M, B> flatMap(Fn1<? super A, ? extends Monad<B, MonadT<M, Mayb
8787
* {@inheritDoc}
8888
*/
8989
@Override
90-
public <B> MaybeT<M, B> discardL(Applicative<B, MonadT<M, Maybe<?>, ?>> appB) {
90+
public <B> MaybeT<M, B> discardL(Applicative<B, MaybeT<M, ?>> appB) {
9191
return MonadT.super.discardL(appB).coerce();
9292
}
9393

9494
/**
9595
* {@inheritDoc}
9696
*/
9797
@Override
98-
public <B> MaybeT<M, A> discardR(Applicative<B, MonadT<M, Maybe<?>, ?>> appB) {
98+
public <B> MaybeT<M, A> discardR(Applicative<B, MaybeT<M, ?>> appB) {
9999
return MonadT.super.discardR(appB).coerce();
100100
}
101101

src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderT.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
* @param <A> the embedded output type
2121
*/
2222
public interface ReaderT<R, M extends Monad<?, M>, A> extends
23-
MonadT<Fn1<R, ?>, M, A>,
23+
MonadT<Fn1<R, ?>, M, A, ReaderT<R, M, ?>>,
2424
Cartesian<R, A, ReaderT<?, M, ?>> {
2525

2626
/**
@@ -57,7 +57,7 @@ default <MA extends Monad<A, M>, N extends Monad<?, N>, B> ReaderT<R, N, B> mapR
5757
* {@inheritDoc}
5858
*/
5959
@Override
60-
default <B> ReaderT<R, M, B> flatMap(Fn1<? super A, ? extends Monad<B, MonadT<Fn1<R, ?>, M, ?>>> f) {
60+
default <B> ReaderT<R, M, B> flatMap(Fn1<? super A, ? extends Monad<B, ReaderT<R, M, ?>>> f) {
6161
return readerT(r -> runReaderT(r).flatMap(a -> f.apply(a).<ReaderT<R, M, B>>coerce().runReaderT(r)));
6262
}
6363

@@ -81,7 +81,7 @@ default <B> ReaderT<R, M, B> fmap(Fn1<? super A, ? extends B> fn) {
8181
* {@inheritDoc}
8282
*/
8383
@Override
84-
default <B> ReaderT<R, M, B> zip(Applicative<Fn1<? super A, ? extends B>, MonadT<Fn1<R, ?>, M, ?>> appFn) {
84+
default <B> ReaderT<R, M, B> zip(Applicative<Fn1<? super A, ? extends B>, ReaderT<R, M, ?>> appFn) {
8585
return readerT(r -> runReaderT(r).zip(appFn.<ReaderT<R, M, Fn1<? super A, ? extends B>>>coerce().runReaderT(r)));
8686
}
8787

@@ -90,23 +90,23 @@ default <B> ReaderT<R, M, B> zip(Applicative<Fn1<? super A, ? extends B>, MonadT
9090
*/
9191
@Override
9292
default <B> Lazy<? extends ReaderT<R, M, B>> lazyZip(
93-
Lazy<? extends Applicative<Fn1<? super A, ? extends B>, MonadT<Fn1<R, ?>, M, ?>>> lazyAppFn) {
93+
Lazy<? extends Applicative<Fn1<? super A, ? extends B>, ReaderT<R, M, ?>>> lazyAppFn) {
9494
return lazyAppFn.fmap(this::zip);
9595
}
9696

9797
/**
9898
* {@inheritDoc}
9999
*/
100100
@Override
101-
default <B> ReaderT<R, M, B> discardL(Applicative<B, MonadT<Fn1<R, ?>, M, ?>> appB) {
101+
default <B> ReaderT<R, M, B> discardL(Applicative<B, ReaderT<R, M, ?>> appB) {
102102
return MonadT.super.discardL(appB).coerce();
103103
}
104104

105105
/**
106106
* {@inheritDoc}
107107
*/
108108
@Override
109-
default <B> ReaderT<R, M, A> discardR(Applicative<B, MonadT<Fn1<R, ?>, M, ?>> appB) {
109+
default <B> ReaderT<R, M, A> discardR(Applicative<B, ReaderT<R, M, ?>> appB) {
110110
return MonadT.super.discardR(appB).coerce();
111111
}
112112

0 commit comments

Comments
 (0)