Skip to content

Commit ef3edfd

Browse files
committed
LiftA2 receives more parameters to aid inference
1 parent e31e3aa commit ef3edfd

File tree

4 files changed

+58
-29
lines changed

4 files changed

+58
-29
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
2525
- `Into3-8` now accept a product of the same cardinality, instead of requiring a tuple
2626
- `CoProduct2-8#project` now return generalized products
2727
- `Choice2-8#project` return tuples
28+
- `liftA2` receives more parameters to aid inference
2829

2930
## [3.0.3] - 2018-05-27
3031
### Added

src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LiftA2.java

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,50 +7,54 @@
77

88
import java.util.function.BiFunction;
99

10-
import static com.jnape.palatable.lambda.functions.Fn2.fn2;
11-
1210
/**
1311
* Lift into and apply a {@link BiFunction} to two {@link Applicative} values, returning the result inside the same
14-
* {@link Applicative} context. Equivalent ot <code>appB.zip(appA.fmap(fn))</code>.
12+
* {@link Applicative} context. Functionally equivalent to <code>appB.zip(appA.fmap(fn))</code>.
1513
*
16-
* @param <A> the function's first argument type
17-
* @param <B> the function's second argument type
18-
* @param <C> the function's return type
19-
* @param <App> the applicative unification type
14+
* @param <A> the function's first argument type
15+
* @param <B> the function's second argument typ
16+
* @param <C> the function's return type
17+
* @param <App> the applicative unification type
18+
* @param <AppA> the inferred first applicative argument type
19+
* @param <AppB> the inferred second applicative argument type
20+
* @param <AppC> the inferred applicative return type
2021
* @see Applicative#zip(Applicative)
2122
*/
22-
public final class LiftA2<A, B, C, App extends Applicative> implements Fn3<BiFunction<? super A, ? super B, ? extends C>,
23-
Applicative<A, App>, Applicative<B, App>, Applicative<C, App>> {
23+
public final class LiftA2<A, B, C, App extends Applicative,
24+
AppA extends Applicative<A, App>,
25+
AppB extends Applicative<B, App>,
26+
AppC extends Applicative<C, App>> implements Fn3<BiFunction<? super A, ? super B, ? extends C>, AppA, AppB, AppC> {
2427

2528
private static final LiftA2 INSTANCE = new LiftA2();
2629

2730
private LiftA2() {
2831
}
2932

3033
@Override
31-
public Applicative<C, App> apply(BiFunction<? super A, ? super B, ? extends C> fn,
32-
Applicative<A, App> appA,
33-
Applicative<B, App> appB) {
34-
return appB.zip(appA.fmap(fn2(fn)));
34+
public AppC apply(BiFunction<? super A, ? super B, ? extends C> fn, AppA appA, AppB appB) {
35+
return appB.zip(appA.fmap(Fn2.<A, B, C>fn2(fn))).coerce();
3536
}
3637

3738
@SuppressWarnings("unchecked")
38-
public static <A, B, C, App extends Applicative> LiftA2<A, B, C, App> liftA2() {
39+
public static <A, B, C, App extends Applicative, AppA extends Applicative<A, App>, AppB extends Applicative<B, App>, AppC extends Applicative<C, App>> LiftA2<A, B, C, App, AppA, AppB, AppC> liftA2() {
3940
return INSTANCE;
4041
}
4142

42-
public static <A, B, C, App extends Applicative> Fn2<Applicative<A, App>, Applicative<B, App>, Applicative<C, App>> liftA2(
43+
public static <A, B, C, App extends Applicative, AppA extends Applicative<A, App>, AppB extends Applicative<B, App>, AppC extends Applicative<C, App>> Fn2<AppA, AppB, AppC> liftA2(
4344
BiFunction<? super A, ? super B, ? extends C> fn) {
44-
return LiftA2.<A, B, C, App>liftA2().apply(fn);
45+
return LiftA2.<A, B, C, App, AppA, AppB, AppC>liftA2().apply(fn);
4546
}
4647

47-
public static <A, B, C, App extends Applicative> Fn1<Applicative<B, App>, Applicative<C, App>> liftA2(
48-
BiFunction<? super A, ? super B, ? extends C> fn, Applicative<A, App> appA) {
49-
return LiftA2.<A, B, C, App>liftA2(fn).apply(appA);
48+
public static <A, B, C, App extends Applicative, AppA extends Applicative<A, App>, AppB extends Applicative<B, App>, AppC extends Applicative<C, App>> Fn1<AppB, AppC> liftA2(
49+
BiFunction<? super A, ? super B, ? extends C> fn,
50+
AppA appA) {
51+
return LiftA2.<A, B, C, App, AppA, AppB, AppC>liftA2(fn).apply(appA);
5052
}
5153

52-
public static <A, B, C, App extends Applicative> Applicative<C, App> liftA2(
53-
BiFunction<? super A, ? super B, ? extends C> fn, Applicative<A, App> appA, Applicative<B, App> appB) {
54-
return LiftA2.<A, B, C, App>liftA2(fn, appA).apply(appB);
54+
public static <A, B, C, App extends Applicative, AppA extends Applicative<A, App>, AppB extends Applicative<B, App>, AppC extends Applicative<C, App>> AppC liftA2(
55+
BiFunction<? super A, ? super B, ? extends C> fn,
56+
AppA appA,
57+
AppB appB) {
58+
return LiftA2.<A, B, C, App, AppA, AppB, AppC>liftA2(fn, appA).apply(appB);
5559
}
5660
}
Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,46 @@
11
package com.jnape.palatable.lambda.functions.builtin.fn3;
22

3-
import com.jnape.palatable.lambda.functor.builtin.Identity;
3+
import com.jnape.palatable.lambda.adt.Either;
4+
import com.jnape.palatable.lambda.adt.Maybe;
45
import org.junit.Test;
56

67
import java.util.function.BiFunction;
78

9+
import static com.jnape.palatable.lambda.adt.Either.left;
810
import static com.jnape.palatable.lambda.adt.Either.right;
9-
import static com.jnape.palatable.lambda.adt.hlist.HList.tuple;
11+
import static com.jnape.palatable.lambda.adt.Maybe.just;
12+
import static com.jnape.palatable.lambda.adt.Maybe.nothing;
1013
import static com.jnape.palatable.lambda.functions.builtin.fn3.LiftA2.liftA2;
1114
import static org.junit.Assert.assertEquals;
1215

1316
public class LiftA2Test {
1417

1518
@Test
16-
public void liftsAndAppliesDyadicFunctionToTwoApplicatives() {
19+
public void inference() {
1720
BiFunction<Integer, Integer, Integer> add = (x, y) -> x + y;
18-
assertEquals(right(3), liftA2(add, right(1), right(2)).coerce());
19-
assertEquals(tuple(1, 5), liftA2(add, tuple(1, 2), tuple(2, 3)).coerce());
20-
assertEquals(new Identity<>(3), liftA2(add, new Identity<>(1), new Identity<>(2)));
21+
22+
Maybe<Integer> a = liftA2(add, just(1), just(2));
23+
assertEquals(just(3), a);
24+
25+
Maybe<Integer> b = liftA2(add, just(1), nothing());
26+
assertEquals(nothing(), b);
27+
28+
Maybe<Integer> c = liftA2(add, nothing(), just(2));
29+
assertEquals(nothing(), c);
30+
31+
Maybe<Integer> d = liftA2(add, nothing(), nothing());
32+
assertEquals(nothing(), d);
33+
34+
Either<String, Integer> e = liftA2(add, Either.<String, Integer>right(1), right(2));
35+
assertEquals(right(3), e);
36+
37+
Either<String, Integer> f = liftA2(add, left("error"), right(2));
38+
assertEquals(left("error"), f);
39+
40+
Either<String, Integer> g = liftA2(add, right(1), left("error"));
41+
assertEquals(left("error"), g);
42+
43+
Either<String, Integer> h = liftA2(add, left("error"), left("another error"));
44+
assertEquals(left("error"), h);
2145
}
2246
}

src/test/java/com/jnape/palatable/lambda/traversable/TraversableTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
public class TraversableTest {
1616

1717
@Test
18-
public void compilation() {
18+
public void inference() {
1919
Either<String, Maybe<Integer>> a = just(Either.<String, Integer>right(1)).traverse(id(), Either::right);
2020
assertEquals(right(just(1)), a);
2121

0 commit comments

Comments
 (0)