Skip to content

Commit 75baa5e

Browse files
committed
Fn0, the function taking "no arguments" (Unit)
1 parent e65b0bc commit 75baa5e

File tree

12 files changed

+252
-6
lines changed

12 files changed

+252
-6
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
1515
- `LambdaMap`, extension point for `j.u.Map`, similar to `LambdaIterable`
1616
- `Sequence#sequence` overloads for `j.u.Map` that traverse via intermediate `LambdaMap` instances
1717
- `Intersection`, a semigroup that behaves like a lazy set intersection on `Iterable`s
18+
- `Fn0`, a function from `Unit` to some value
19+
- `Fn1#thunk`, producing an `Fn0`
1820

1921
### Changed
2022
- `Tuple2-8` now implement `Product2-8`
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
package com.jnape.palatable.lambda.functions;
2+
3+
import com.jnape.palatable.lambda.adt.Unit;
4+
import com.jnape.palatable.lambda.functor.Applicative;
5+
import com.jnape.palatable.lambda.monad.Monad;
6+
7+
import java.util.function.Function;
8+
import java.util.function.Supplier;
9+
10+
import static com.jnape.palatable.lambda.adt.Unit.UNIT;
11+
12+
/**
13+
* A function taking "no arguments", implemented as an <code>{@link Fn1}&lt;{@link Unit}, A&gt;</code>.
14+
*
15+
* @param <A> the result type
16+
* @see Fn1
17+
* @see Supplier
18+
*/
19+
@FunctionalInterface
20+
public interface Fn0<A> extends Fn1<Unit, A>, Supplier<A> {
21+
22+
/**
23+
* Invoke this function with {@link Unit}.
24+
*
25+
* @param unit the only allowed input
26+
* @return the result value
27+
*/
28+
@Override
29+
A apply(Unit unit);
30+
31+
/**
32+
* Apply this {@link Fn0}, supplying {@link Unit} as the input.
33+
*
34+
* @return the output
35+
*/
36+
default A apply() {
37+
return apply(UNIT);
38+
}
39+
40+
@Override
41+
default <B> Fn0<B> flatMap(Function<? super A, ? extends Monad<B, Fn1<Unit, ?>>> f) {
42+
return Fn1.super.flatMap(f)::apply;
43+
}
44+
45+
@Override
46+
default <B> Fn0<B> fmap(Function<? super A, ? extends B> f) {
47+
return Fn1.super.fmap(f)::apply;
48+
}
49+
50+
@Override
51+
default <B> Fn0<B> pure(B b) {
52+
return Fn1.super.pure(b)::apply;
53+
}
54+
55+
@Override
56+
default <B> Fn0<B> zip(Applicative<Function<? super A, ? extends B>, Fn1<Unit, ?>> appFn) {
57+
return Fn1.super.zip(appFn)::apply;
58+
}
59+
60+
@Override
61+
default <B> Fn0<B> zip(Fn2<Unit, A, B> appFn) {
62+
return Fn1.super.zip(appFn)::apply;
63+
}
64+
65+
@Override
66+
default <B> Fn0<B> discardL(Applicative<B, Fn1<Unit, ?>> appB) {
67+
return Fn1.super.discardL(appB)::apply;
68+
}
69+
70+
@Override
71+
default <B> Fn0<A> discardR(Applicative<B, Fn1<Unit, ?>> appB) {
72+
return Fn1.super.discardR(appB)::apply;
73+
}
74+
75+
@Override
76+
default <B> Fn0<B> diMapR(Function<? super A, ? extends B> fn) {
77+
return Fn1.super.diMapR(fn)::apply;
78+
}
79+
80+
@Override
81+
default <Z> Fn1<Z, A> compose(Function<? super Z, ? extends Unit> before) {
82+
return Fn1.super.compose(before)::apply;
83+
}
84+
85+
@Override
86+
default <B> Fn0<B> andThen(Function<? super A, ? extends B> after) {
87+
return Fn1.super.andThen(after)::apply;
88+
}
89+
90+
@Override
91+
default A get() {
92+
return apply(UNIT);
93+
}
94+
95+
/**
96+
* Convenience method for converting a {@link Supplier} to an {@link Fn0}.
97+
*
98+
* @param supplier the supplier
99+
* @param <A> the output type
100+
* @return the {@link Fn0}
101+
*/
102+
static <A> Fn0<A> fn0(Supplier<A> supplier) {
103+
return __ -> supplier.get();
104+
}
105+
106+
/**
107+
* Static factory method for coercing a lambda to an {@link Fn0}.
108+
*
109+
* @param fn the lambda to coerce
110+
* @param <A> the output type
111+
* @return the {@link Fn0}
112+
*/
113+
static <A> Fn0<A> fn0(Fn0<A> fn) {
114+
return fn;
115+
}
116+
117+
/**
118+
* Static factory method for adapting a {@link Runnable} to an <code>{@link Fn0}&lt;{@link Unit}&gt;</code>.
119+
*
120+
* @param fn the {@link Runnable}
121+
* @return the {@link Fn0}
122+
*/
123+
static Fn0<Unit> fn0(Runnable fn) {
124+
return unit -> {
125+
fn.run();
126+
return unit;
127+
};
128+
}
129+
130+
/**
131+
* Static factory method for adapting a {@link Function} to an {@link Fn0}.
132+
*
133+
* @param fn the {@link Function}
134+
* @param <A> the output type
135+
* @return the {@link Fn0}
136+
*/
137+
static <A> Fn0<A> fn0(Function<Unit, A> fn) {
138+
return fn0(() -> fn.apply(UNIT));
139+
}
140+
}

src/main/java/com/jnape/palatable/lambda/functions/Fn1.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,17 @@ public interface Fn1<A, B> extends Monad<B, Fn1<A, ?>>, Profunctor<A, B, Fn1>, F
2727
*/
2828
B apply(A a);
2929

30+
/**
31+
* Convert this {@link Fn1} to an {@link Fn0} by supplying an argument to this function. Useful for fixing an
32+
* argument now, but deferring application until a later time.
33+
*
34+
* @param a the argument
35+
* @return an {@link Fn0}
36+
*/
37+
default Fn0<B> thunk(A a) {
38+
return __ -> apply(a);
39+
}
40+
3041
@Override
3142
default <C> Fn1<A, C> flatMap(Function<? super B, ? extends Monad<C, Fn1<A, ?>>> f) {
3243
return a -> f.apply(apply(a)).<Fn1<A, C>>coerce().apply(a);

src/main/java/com/jnape/palatable/lambda/functions/Fn3.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ static <A, B, C, D> Fn3<A, B, C, D> fn3(Fn2<A, B, Fn1<C, D>> curriedFn2) {
128128
}
129129

130130
/**
131-
* Static factory method for coercing a lambda to an {@link Fn3};
131+
* Static factory method for coercing a lambda to an {@link Fn3}.
132132
*
133133
* @param fn the lambda to coerce
134134
* @param <A> the first input argument type

src/main/java/com/jnape/palatable/lambda/functions/Fn4.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ static <A, B, C, D, E> Fn4<A, B, C, D, E> fn4(Fn3<A, B, C, Fn1<D, E>> curriedFn3
160160
}
161161

162162
/**
163-
* Static factory method for coercing a lambda to an {@link Fn4};
163+
* Static factory method for coercing a lambda to an {@link Fn4}.
164164
*
165165
* @param fn the lambda to coerce
166166
* @param <A> the first input argument type

src/main/java/com/jnape/palatable/lambda/functions/Fn5.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ static <A, B, C, D, E, F> Fn5<A, B, C, D, E, F> fn5(Fn4<A, B, C, D, Fn1<E, F>> c
195195
}
196196

197197
/**
198-
* Static factory method for coercing a lambda to an {@link Fn5};
198+
* Static factory method for coercing a lambda to an {@link Fn5}.
199199
*
200200
* @param fn the lambda to coerce
201201
* @param <A> the first input argument type

src/main/java/com/jnape/palatable/lambda/functions/Fn6.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ static <A, B, C, D, E, F, G> Fn6<A, B, C, D, E, F, G> fn6(Fn5<A, B, C, D, E, Fn1
233233
}
234234

235235
/**
236-
* Static factory method for coercing a lambda to an {@link Fn6};
236+
* Static factory method for coercing a lambda to an {@link Fn6}.
237237
*
238238
* @param fn the lambda to coerce
239239
* @param <A> the first input argument type

src/main/java/com/jnape/palatable/lambda/functions/Fn7.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ static <A, B, C, D, E, F, G, H> Fn7<A, B, C, D, E, F, G, H> fn7(Fn6<A, B, C, D,
274274
}
275275

276276
/**
277-
* Static factory method for coercing a lambda to an {@link Fn7};
277+
* Static factory method for coercing a lambda to an {@link Fn7}.
278278
*
279279
* @param fn the lambda to coerce
280280
* @param <A> the first input argument type

src/main/java/com/jnape/palatable/lambda/functions/Fn8.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,7 @@ static <A, B, C, D, E, F, G, H, I> Fn8<A, B, C, D, E, F, G, H, I> fn8(
324324
}
325325

326326
/**
327-
* Static factory method for coercing a lambda to an {@link Fn8};
327+
* Static factory method for coercing a lambda to an {@link Fn8}.
328328
*
329329
* @param fn the lambda to coerce
330330
* @param <A> the first input argument type
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.jnape.palatable.lambda.functions;
2+
3+
import com.jnape.palatable.traitor.annotations.TestTraits;
4+
import com.jnape.palatable.traitor.runners.Traits;
5+
import org.junit.runner.RunWith;
6+
import testsupport.EqualityAwareFn0;
7+
import testsupport.traits.ApplicativeLaws;
8+
import testsupport.traits.FunctorLaws;
9+
import testsupport.traits.MonadLaws;
10+
11+
import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly;
12+
13+
@RunWith(Traits.class)
14+
public class Fn0Test {
15+
16+
@TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class})
17+
public Fn0<Integer> testSubject() {
18+
return new EqualityAwareFn0<>(constantly(1)::apply);
19+
}
20+
}

src/test/java/com/jnape/palatable/lambda/functions/Fn1Test.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,10 @@ public void fn1() {
3535
Function<String, Integer> parseInt = Integer::parseInt;
3636
assertEquals((Integer) 1, Fn1.fn1(parseInt).apply("1"));
3737
}
38+
39+
@Test
40+
public void thunk() {
41+
Fn1<Integer, String> toString = Object::toString;
42+
assertEquals("1", toString.thunk(1).apply());
43+
}
3844
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package testsupport;
2+
3+
import com.jnape.palatable.lambda.adt.Unit;
4+
import com.jnape.palatable.lambda.functions.Fn0;
5+
import com.jnape.palatable.lambda.functions.Fn1;
6+
import com.jnape.palatable.lambda.functor.Applicative;
7+
import com.jnape.palatable.lambda.monad.Monad;
8+
9+
import java.util.function.Function;
10+
11+
import static com.jnape.palatable.lambda.adt.Unit.UNIT;
12+
import static java.util.Objects.hash;
13+
14+
public final class EqualityAwareFn0<A> implements Fn0<A> {
15+
private final Fn0<A> fn;
16+
17+
public EqualityAwareFn0(Fn0<A> fn) {
18+
this.fn = fn;
19+
}
20+
21+
@Override
22+
public A apply(Unit unit) {
23+
return fn.apply(unit);
24+
}
25+
26+
@Override
27+
public <B> EqualityAwareFn0<B> flatMap(Function<? super A, ? extends Monad<B, Fn1<Unit, ?>>> f) {
28+
return new EqualityAwareFn0<>(fn.flatMap(f));
29+
}
30+
31+
@Override
32+
public <B> EqualityAwareFn0<B> fmap(Function<? super A, ? extends B> f) {
33+
return new EqualityAwareFn0<>(fn.fmap(f));
34+
}
35+
36+
@Override
37+
public <B> EqualityAwareFn0<B> zip(Applicative<Function<? super A, ? extends B>, Fn1<Unit, ?>> appFn) {
38+
return new EqualityAwareFn0<>(fn.zip(appFn));
39+
}
40+
41+
@Override
42+
public <B> EqualityAwareFn0<B> pure(B b) {
43+
return new EqualityAwareFn0<>(fn.pure(b));
44+
}
45+
46+
47+
@Override
48+
public <B> EqualityAwareFn0<B> discardL(Applicative<B, Fn1<Unit, ?>> appB) {
49+
return new EqualityAwareFn0<>(fn.discardL(appB));
50+
}
51+
52+
@Override
53+
public <B> EqualityAwareFn0<A> discardR(Applicative<B, Fn1<Unit, ?>> appB) {
54+
return new EqualityAwareFn0<>(fn.discardR(appB));
55+
}
56+
57+
@Override
58+
@SuppressWarnings("unchecked")
59+
public boolean equals(Object other) {
60+
return other instanceof Fn0 && ((Fn0<A>) other).apply(UNIT).equals(apply(UNIT));
61+
}
62+
63+
@Override
64+
public int hashCode() {
65+
return hash(fn);
66+
}
67+
}

0 commit comments

Comments
 (0)