Skip to content

Commit 45724d5

Browse files
committed
LazyT, a monad transformer for Lazy
1 parent a79e760 commit 45724d5

4 files changed

Lines changed: 197 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,15 @@ might need to be reworked, and subtyping is obviously no longer supported.
2424
- `MaybeT`, a monad transformer for `Maybe`
2525
- `EitherT`, a monad transformer for `Either`
2626
- `IdentityT`, a monad transformer for `Identity`
27+
- `LazyT`, a monad transformer for `Lazy`
2728
- `Endo`, a monoid formed by `Fn1` under composition
2829
- `State`, the state `Monad`
2930
- `Downcast`, a function supporting unchecked down-casting
3031
- `Cocartesian`, profunctorial strength in cocartesian coproduct terms
32+
- `Prism`, an `Optic` that is nearly an `Iso` but can fail in one direction
33+
- `Market`, `Tagged`, profunctors supporting optics
34+
- `Re` for viewing an `Optic` in one direction reliably
35+
- `Pre` for viewing at most one value from an `Optic` in one direction
3136

3237
## [3.3.0] - 2019-02-18
3338
### Added

src/main/java/com/jnape/palatable/lambda/functor/builtin/Lazy.java

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44
import com.jnape.palatable.lambda.functions.Fn0;
55
import com.jnape.palatable.lambda.functor.Applicative;
66
import com.jnape.palatable.lambda.monad.Monad;
7+
import com.jnape.palatable.lambda.traversable.Traversable;
78

89
import java.util.LinkedList;
10+
import java.util.Objects;
911
import java.util.function.Function;
1012
import java.util.function.Supplier;
1113

@@ -21,7 +23,7 @@
2123
*
2224
* @param <A> the value type
2325
*/
24-
public abstract class Lazy<A> implements Monad<A, Lazy<?>> {
26+
public abstract class Lazy<A> implements Monad<A, Lazy<?>>, Traversable<A, Lazy<?>> {
2527

2628
private Lazy() {
2729
}
@@ -44,6 +46,18 @@ public <B> Lazy<B> flatMap(Function<? super A, ? extends Monad<B, Lazy<?>>> f) {
4446
return new Compose<>(source, flatMap);
4547
}
4648

49+
/**
50+
* {@inheritDoc}
51+
*/
52+
@Override
53+
@SuppressWarnings("unchecked")
54+
public <B, App extends Applicative<?, App>, TravB extends Traversable<B, Lazy<?>>,
55+
AppB extends Applicative<B, App>,
56+
AppTrav extends Applicative<TravB, App>> AppTrav traverse(Function<? super A, ? extends AppB> fn,
57+
Function<? super TravB, ? extends AppTrav> pure) {
58+
return fn.apply(value()).fmap(b -> (TravB) lazy(b)).coerce();
59+
}
60+
4761
/**
4862
* {@inheritDoc}
4963
*/
@@ -84,6 +98,21 @@ public final <B> Lazy<A> discardR(Applicative<B, Lazy<?>> appB) {
8498
return Monad.super.discardR(appB).coerce();
8599
}
86100

101+
@Override
102+
public boolean equals(Object other) {
103+
return other instanceof Lazy<?> && Objects.equals(value(), ((Lazy<?>) other).value());
104+
}
105+
106+
@Override
107+
public int hashCode() {
108+
return Objects.hash(value());
109+
}
110+
111+
@Override
112+
public String toString() {
113+
return "Lazy{value=" + value() + "}";
114+
}
115+
87116
/**
88117
* Lift a pure value into a lazy computation.
89118
*
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
package com.jnape.palatable.lambda.monad.transformer.builtin;
2+
3+
import com.jnape.palatable.lambda.functor.Applicative;
4+
import com.jnape.palatable.lambda.functor.Functor;
5+
import com.jnape.palatable.lambda.functor.builtin.Compose;
6+
import com.jnape.palatable.lambda.functor.builtin.Lazy;
7+
import com.jnape.palatable.lambda.monad.Monad;
8+
import com.jnape.palatable.lambda.monad.transformer.MonadT;
9+
10+
import java.util.Objects;
11+
import java.util.function.Function;
12+
13+
import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy;
14+
15+
/**
16+
* A {@link MonadT monad transformer} for {@link Lazy}. Note that {@link LazyT#flatMap(Function)} must force its value.
17+
*
18+
* @param <M> the outer {@link Monad}
19+
* @param <A> the carrier type
20+
*/
21+
public class LazyT<M extends Monad<?, M>, A> implements MonadT<M, Lazy<?>, A> {
22+
23+
private final Monad<Lazy<A>, M> mla;
24+
25+
private LazyT(Monad<Lazy<A>, M> mla) {
26+
this.mla = mla;
27+
}
28+
29+
/**
30+
* {@inheritDoc}
31+
*/
32+
@Override
33+
public <GA extends Monad<A, Lazy<?>>, FGA extends Monad<GA, M>> FGA run() {
34+
return mla.<GA>fmap(Functor::coerce).coerce();
35+
}
36+
37+
/**
38+
* {@inheritDoc}
39+
*/
40+
@Override
41+
public <B> LazyT<M, B> flatMap(Function<? 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()));
43+
}
44+
45+
/**
46+
* {@inheritDoc}
47+
*/
48+
@Override
49+
public <B> LazyT<M, B> pure(B b) {
50+
return new LazyT<>(mla.pure(lazy(b)));
51+
}
52+
53+
/**
54+
* {@inheritDoc}
55+
*/
56+
@Override
57+
public <B> LazyT<M, B> fmap(Function<? super A, ? extends B> fn) {
58+
return MonadT.super.<B>fmap(fn).coerce();
59+
}
60+
61+
/**
62+
* {@inheritDoc}
63+
*/
64+
@Override
65+
public <B> LazyT<M, B> zip(Applicative<Function<? super A, ? extends B>, MonadT<M, Lazy<?>, ?>> appFn) {
66+
return MonadT.super.zip(appFn).coerce();
67+
}
68+
69+
/**
70+
* {@inheritDoc}
71+
*/
72+
@Override
73+
public <B> Lazy<LazyT<M, B>> lazyZip(
74+
Lazy<? extends Applicative<Function<? super A, ? extends B>, MonadT<M, Lazy<?>, ?>>> lazyAppFn) {
75+
return new Compose<>(mla)
76+
.lazyZip(lazyAppFn.fmap(lazyT -> new Compose<>(
77+
lazyT.<LazyT<M, Function<? super A, ? extends B>>>coerce()
78+
.<Lazy<Function<? super A, ? extends B>>,
79+
Monad<Lazy<Function<? super A, ? extends B>>, M>>run())))
80+
.fmap(compose -> lazyT(compose.getCompose()));
81+
}
82+
83+
/**
84+
* {@inheritDoc}
85+
*/
86+
@Override
87+
public <B> LazyT<M, B> discardL(Applicative<B, MonadT<M, Lazy<?>, ?>> appB) {
88+
return MonadT.super.discardL(appB).coerce();
89+
}
90+
91+
/**
92+
* {@inheritDoc}
93+
*/
94+
@Override
95+
public <B> LazyT<M, A> discardR(Applicative<B, MonadT<M, Lazy<?>, ?>> appB) {
96+
return MonadT.super.discardR(appB).coerce();
97+
}
98+
99+
@Override
100+
public boolean equals(Object other) {
101+
return other instanceof LazyT<?, ?> && Objects.equals(mla, ((LazyT<?, ?>) other).mla);
102+
}
103+
104+
@Override
105+
public int hashCode() {
106+
return Objects.hash(mla);
107+
}
108+
109+
@Override
110+
public String toString() {
111+
return "LazyT{mla=" + mla + '}';
112+
}
113+
114+
/**
115+
* Static factory method for lifting a <code>{@link Monad}&lt;{@link Lazy}&lt;A&gt;, M&gt;</code> into a
116+
* {@link LazyT}.
117+
*
118+
* @param mla the {@link Monad}&lt;{@link Lazy}&lt;A&gt;, M&gt;
119+
* @param <M> the outer {@link Monad} unification parameter
120+
* @param <A> the carrier type
121+
* @return the new {@link LazyT}
122+
*/
123+
public static <M extends Monad<?, M>, A> LazyT<M, A> lazyT(Monad<Lazy<A>, M> mla) {
124+
return new LazyT<>(mla);
125+
}
126+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.jnape.palatable.lambda.monad.transformer.builtin;
2+
3+
import com.jnape.palatable.lambda.adt.Maybe;
4+
import com.jnape.palatable.traitor.annotations.TestTraits;
5+
import com.jnape.palatable.traitor.runners.Traits;
6+
import org.junit.Test;
7+
import org.junit.runner.RunWith;
8+
import testsupport.traits.ApplicativeLaws;
9+
import testsupport.traits.FunctorLaws;
10+
import testsupport.traits.MonadLaws;
11+
12+
import static com.jnape.palatable.lambda.adt.Maybe.just;
13+
import static com.jnape.palatable.lambda.adt.Maybe.nothing;
14+
import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy;
15+
import static com.jnape.palatable.lambda.monad.transformer.builtin.LazyT.lazyT;
16+
import static org.junit.Assert.assertEquals;
17+
18+
@RunWith(Traits.class)
19+
public class LazyTTest {
20+
21+
@TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class})
22+
public LazyT<Maybe<?>, Integer> testSubject() {
23+
return lazyT(just(lazy(1)));
24+
}
25+
26+
@Test
27+
public void lazyZip() {
28+
assertEquals(lazyT(just(lazy(2))),
29+
lazyT(just(lazy(1)))
30+
.lazyZip(lazy(lazyT(just(lazy(x -> x + 1))))).value());
31+
assertEquals(lazyT(nothing()),
32+
lazyT(nothing()).lazyZip(lazy(() -> {
33+
throw new AssertionError();
34+
})).value());
35+
}
36+
}

0 commit comments

Comments
 (0)