Skip to content

Commit 68a20e0

Browse files
committed
Sequence is now better at inferring the target type
1 parent d43695a commit 68a20e0

File tree

3 files changed

+62
-35
lines changed

3 files changed

+62
-35
lines changed

CHANGELOG.md

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](http://keepachangelog.com/).
55

66
## [Unreleased]
7+
### Changed
8+
- ***Breaking Change***: `Sequence` now has two more type parameters to aid in inference
9+
- `Bifunctor` is now a `BoundedBifunctor` where both parameter upper bounds are `Object`
10+
- `Peek2` now accepts the more general `BoundedBifunctor`
11+
- `Identity`, `Compose`, and `Const` functors all have better `toString` implementations
12+
- `Into3-8` now supports functions with parameter variance
13+
- `HListLens#tail` is now covariant in `Tail` parameter
14+
715
### Added
816
- `BoundedBifunctor`, a `Bifunctor` super type that offers upper bounds for both parameters
917
- `Try`, a `Monad` representing an expression-like analog of `try/catch/finally`
@@ -12,13 +20,6 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
1220
- `Kleisli`, the abstract representation of a `Kleisli` arrow (`Monad#flatMap`) as an `Fn1`
1321
- `These`, a `CoProduct3` of `A`, `B`, or `Tuple2<A,B>`
1422

15-
### Changed
16-
- `Bifunctor` is now a `BoundedBifunctor` where both parameter upper bounds are `Object`
17-
- `Peek2` now accepts the more general `BoundedBifunctor`
18-
- `Identity`, `Compose`, and `Const` functors all have better `toString` implementations
19-
- `Into3-8` now supports functions with parameter variance
20-
- `HListLens#tail` is now covariant in `Tail` parameter
21-
2223
### Deprecated
2324
- `Either#trying` in favor of `Try#trying`
2425

src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Sequence.java

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,16 @@
2323
* @param <A> the Traversable element type
2424
* @param <App> the Applicative unification parameter
2525
* @param <Trav> the Traversable unification parameter
26+
* @param <AppA> the Applicative instance wrapped in the input Traversable
27+
* @param <TravA> the Traversable instance wrapped in the output Applicative
2628
* @param <AppTrav> the concrete parametrized output Applicative type
2729
* @param <TravApp> the concrete parametrized input Traversable type
2830
*/
29-
public final class Sequence<A, App extends Applicative, Trav extends Traversable, AppTrav extends Applicative<? extends Traversable<A, Trav>, App>,
30-
TravApp extends Traversable<? extends Applicative<A, App>, Trav>> implements Fn2<TravApp, Function<? super Traversable<A, Trav>, ? extends AppTrav>, AppTrav> {
31+
public final class Sequence<A, App extends Applicative, Trav extends Traversable,
32+
AppA extends Applicative<A, App>,
33+
TravA extends Traversable<A, Trav>,
34+
AppTrav extends Applicative<TravA, App>,
35+
TravApp extends Traversable<AppA, Trav>> implements Fn2<TravApp, Function<TravA, ? extends AppTrav>, AppTrav> {
3136

3237
private static final Sequence INSTANCE = new Sequence();
3338

@@ -36,43 +41,47 @@ private Sequence() {
3641

3742
@Override
3843
@SuppressWarnings("unchecked")
39-
public AppTrav apply(TravApp traversable, Function<? super Traversable<A, Trav>, ? extends AppTrav> pure) {
40-
return (AppTrav) traversable.traverse(id(), pure);
44+
public AppTrav apply(TravApp traversable, Function<TravA, ? extends AppTrav> pure) {
45+
return (AppTrav) traversable.traverse(id(), trav -> pure.apply((TravA) trav));
4146
}
4247

4348
@SuppressWarnings("unchecked")
4449
public static <A, App extends Applicative, Trav extends Traversable,
45-
AppTrav extends Applicative<? extends Traversable<A, Trav>, App>,
46-
TravApp extends Traversable<? extends Applicative<A, App>, Trav>> Sequence<A, App, Trav, AppTrav, TravApp> sequence() {
50+
AppA extends Applicative<A, App>,
51+
TravA extends Traversable<A, Trav>,
52+
AppTrav extends Applicative<TravA, App>,
53+
TravApp extends Traversable<AppA, Trav>> Sequence<A, App, Trav, AppA, TravA, AppTrav, TravApp> sequence() {
4754
return INSTANCE;
4855
}
4956

5057
public static <A, App extends Applicative, Trav extends Traversable,
51-
AppTrav extends Applicative<? extends Traversable<A, Trav>, App>,
52-
TravApp extends Traversable<? extends Applicative<A, App>, Trav>> Fn1<Function<? super Traversable<A, Trav>, ? extends AppTrav>, AppTrav> sequence(
58+
AppA extends Applicative<A, App>,
59+
TravA extends Traversable<A, Trav>,
60+
AppTrav extends Applicative<TravA, App>,
61+
TravApp extends Traversable<AppA, Trav>> Fn1<Function<TravA, ? extends AppTrav>, AppTrav> sequence(
5362
TravApp traversable) {
54-
return Sequence.<A, App, Trav, AppTrav, TravApp>sequence().apply(traversable);
63+
return Sequence.<A, App, Trav, AppA, TravA, AppTrav, TravApp>sequence().apply(traversable);
5564
}
5665

5766
public static <A, App extends Applicative, Trav extends Traversable,
58-
AppTrav extends Applicative<? extends Traversable<A, Trav>, App>,
59-
TravApp extends Traversable<? extends Applicative<A, App>, Trav>> AppTrav sequence(TravApp traversable,
60-
Function<? super Traversable<A, Trav>, ? extends AppTrav> pure) {
61-
return Sequence.<A, App, Trav, AppTrav, TravApp>sequence(traversable).apply(pure);
67+
TravA extends Traversable<A, Trav>,
68+
AppA extends Applicative<A, App>,
69+
AppTrav extends Applicative<TravA, App>,
70+
TravApp extends Traversable<AppA, Trav>> AppTrav sequence(TravApp traversable,
71+
Function<TravA, ? extends AppTrav> pure) {
72+
return Sequence.<A, App, Trav, AppA, TravA, AppTrav, TravApp>sequence(traversable).apply(pure);
6273
}
6374

64-
@SuppressWarnings("unchecked")
65-
public static <A, App extends Applicative, AppIterable extends Applicative<Iterable<A>, App>, IterableApp extends Iterable<? extends Applicative<A, App>>> Fn1<Function<? super Iterable<A>, ? extends AppIterable>, AppIterable> sequence(
66-
IterableApp iterableApp) {
67-
return pure ->
68-
(AppIterable) sequence(LambdaIterable.wrap(iterableApp), x -> pure.apply(((LambdaIterable<A>) x).unwrap())
69-
.fmap(LambdaIterable::wrap))
70-
.fmap(LambdaIterable::unwrap);
75+
@SuppressWarnings({"unchecked", "RedundantTypeArguments"})
76+
public static <A, App extends Applicative, AppA extends Applicative<A, App>, AppIterable extends Applicative<Iterable<A>, App>, IterableApp extends Iterable<AppA>>
77+
Fn1<Function<Iterable<A>, ? extends AppIterable>, AppIterable> sequence(IterableApp iterableApp) {
78+
return pure -> (AppIterable) Sequence.<A, App, LambdaIterable, LambdaIterable<A>, AppA, Applicative<LambdaIterable<A>, App>, LambdaIterable<AppA>>sequence(
79+
LambdaIterable.wrap(iterableApp), x -> pure.apply(x.unwrap()).fmap(LambdaIterable::wrap))
80+
.fmap(LambdaIterable::unwrap);
7181
}
7282

73-
public static <A, App extends Applicative, AppIterable extends Applicative<Iterable<A>, App>,
74-
IterableApp extends Iterable<? extends Applicative<A, App>>> AppIterable sequence(IterableApp iterableApp,
75-
Function<? super Iterable<A>, ? extends AppIterable> pure) {
76-
return Sequence.<A, App, AppIterable, IterableApp>sequence(iterableApp).apply(pure);
83+
public static <A, App extends Applicative, AppA extends Applicative<A, App>, AppIterable extends Applicative<Iterable<A>, App>, IterableApp extends Iterable<AppA>>
84+
AppIterable sequence(IterableApp iterableApp, Function<Iterable<A>, ? extends AppIterable> pure) {
85+
return Sequence.<A, App, AppA, AppIterable, IterableApp>sequence(iterableApp).apply(pure);
7786
}
7887
}

src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/SequenceTest.java

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
package com.jnape.palatable.lambda.functions.builtin.fn2;
22

33
import com.jnape.palatable.lambda.adt.Either;
4+
import com.jnape.palatable.lambda.adt.Maybe;
45
import com.jnape.palatable.lambda.functor.builtin.Compose;
56
import com.jnape.palatable.lambda.functor.builtin.Identity;
67
import org.junit.Test;
78

89
import java.util.function.Function;
910

1011
import static com.jnape.palatable.lambda.adt.Either.right;
12+
import static com.jnape.palatable.lambda.adt.Maybe.just;
1113
import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id;
1214
import static com.jnape.palatable.lambda.functions.builtin.fn2.Sequence.sequence;
1315
import static java.util.Arrays.asList;
@@ -29,15 +31,15 @@ public void naturality() {
2931
@Test
3032
public void identity() {
3133
Either<String, Identity<Integer>> traversable = right(new Identity<>(1));
32-
assertEquals(sequence(traversable.fmap(Identity::new), Identity::new),
33-
new Identity<>(traversable));
34+
assertEquals(new Identity<>(traversable),
35+
sequence(traversable.fmap(Identity::new), Identity::new));
3436
}
3537

3638
@Test
3739
public void composition() {
3840
Either<String, Identity<Either<String, Integer>>> traversable = right(new Identity<>(right(1)));
39-
assertEquals(sequence(traversable.fmap(x -> new Compose<>(x.fmap(id()))), x -> new Compose<>(new Identity<>(right(x)))),
40-
new Compose<>(sequence(traversable, Identity::new).fmap(x -> sequence(x, Either::right)).fmap(id())));
41+
assertEquals(new Compose<>(sequence(traversable, Identity::new).fmap(x -> sequence(x, Either::right)).fmap(id())),
42+
sequence(traversable.fmap(x -> new Compose<>(x.fmap(id()))), x -> new Compose<>(new Identity<>(right(x)))));
4143
}
4244

4345
@Test
@@ -46,4 +48,19 @@ public void iterableSpecialization() {
4648
.orThrow(l -> new AssertionError("Expected a right value, but was a left value of <" + l + ">")),
4749
iterates(1, 2));
4850
}
51+
52+
@Test
53+
public void compilation() {
54+
Either<String, Maybe<Integer>> a = sequence(just(right(1)), Either::right);
55+
assertEquals(right(just(1)), a);
56+
57+
Maybe<Either<String, Integer>> b = sequence(right(just(1)), Maybe::just);
58+
assertEquals(just(right(1)), b);
59+
60+
Either<String, Maybe<Integer>> c = sequence(b, Either::right);
61+
assertEquals(a, c);
62+
63+
Maybe<Iterable<Integer>> d = sequence(asList(just(1), just(2)), Maybe::just);
64+
assertThat(d.orElseThrow(AssertionError::new), iterates(1, 2));
65+
}
4966
}

0 commit comments

Comments
 (0)