Skip to content

Commit d95e2e5

Browse files
committed
Merge branch 'functor-unification' into recursion-schemes
2 parents 51646db + e88df4a commit d95e2e5

File tree

11 files changed

+269
-4
lines changed

11 files changed

+269
-4
lines changed

src/main/java/com/jnape/palatable/lambda/adt/hmap/TypeSafeKey.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
*
1111
* @param <T> The type of the value that this key maps to inside an HMap
1212
*/
13-
@SuppressWarnings("unused")
1413
public interface TypeSafeKey<T> {
1514

1615
/**
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.jnape.palatable.lambda.functions.builtin.fn2;
2+
3+
import com.jnape.palatable.lambda.functions.Fn1;
4+
import com.jnape.palatable.lambda.functions.Fn2;
5+
import com.jnape.palatable.lambda.iterators.ConsingIterator;
6+
7+
/**
8+
* Prepend an element to an <code>Iterable</code>.
9+
*
10+
* @param <A> the Iterable element type
11+
*/
12+
public final class Cons<A> implements Fn2<A, Iterable<A>, Iterable<A>> {
13+
14+
private static final Cons INSTANCE = new Cons();
15+
16+
private Cons() {
17+
}
18+
19+
@Override
20+
public Iterable<A> apply(A a, Iterable<A> as) {
21+
return () -> new ConsingIterator<>(a, as);
22+
}
23+
24+
@SuppressWarnings("unchecked")
25+
public static <A> Cons<A> cons() {
26+
return (Cons<A>) INSTANCE;
27+
}
28+
29+
public static <A> Fn1<Iterable<A>, Iterable<A>> cons(A a) {
30+
return Cons.<A>cons().apply(a);
31+
}
32+
33+
public static <A> Iterable<A> cons(A a, Iterable<A> as) {
34+
return cons(a).apply(as);
35+
}
36+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package com.jnape.palatable.lambda.iterators;
2+
3+
import java.util.Iterator;
4+
import java.util.NoSuchElementException;
5+
import java.util.function.Supplier;
6+
7+
public final class ConsingIterator<A> implements Iterator<A> {
8+
9+
private final A head;
10+
private final Supplier<Iterator<A>> asSupplier;
11+
private Iterator<A> asIterator;
12+
private boolean iteratedHead;
13+
14+
public ConsingIterator(A head, Iterable<A> as) {
15+
this.head = head;
16+
this.asSupplier = as::iterator;
17+
iteratedHead = false;
18+
}
19+
20+
@Override
21+
public boolean hasNext() {
22+
if (!iteratedHead)
23+
return true;
24+
25+
if (asIterator == null)
26+
asIterator = asSupplier.get();
27+
28+
return asIterator.hasNext();
29+
}
30+
31+
@Override
32+
public A next() {
33+
if (!hasNext())
34+
throw new NoSuchElementException();
35+
36+
if (!iteratedHead) {
37+
iteratedHead = true;
38+
return head;
39+
}
40+
41+
while (asIterator instanceof ConsingIterator && ((ConsingIterator) asIterator).iteratedHead) {
42+
ConsingIterator<A> cons = (ConsingIterator<A>) asIterator;
43+
if (cons.iteratedHead && cons.asIterator != null)
44+
asIterator = cons.asIterator;
45+
}
46+
47+
return asIterator.next();
48+
}
49+
}

src/main/java/com/jnape/palatable/lambda/lens/functions/Over.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
*/
2626
public final class Over<S, T, A, B> implements Fn3<Lens<S, T, A, B>, Function<? super A, ? extends B>, S, T> {
2727

28+
private static final Over INSTANCE = new Over();
29+
2830
private Over() {
2931
}
3032

@@ -35,8 +37,9 @@ public T apply(Lens<S, T, A, B> lens, Function<? super A, ? extends B> fn, S s)
3537
.runIdentity();
3638
}
3739

40+
@SuppressWarnings("unchecked")
3841
public static <S, T, A, B> Over<S, T, A, B> over() {
39-
return new Over<>();
42+
return (Over<S, T, A, B>) INSTANCE;
4043
}
4144

4245
public static <S, T, A, B> Fn2<Function<? super A, ? extends B>, S, T> over(

src/main/java/com/jnape/palatable/lambda/lens/functions/Set.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
*/
2626
public final class Set<S, T, A, B> implements Fn3<Lens<S, T, A, B>, B, S, T> {
2727

28+
private static final Set INSTANCE = new Set();
29+
2830
private Set() {
2931
}
3032

@@ -33,8 +35,9 @@ public T apply(Lens<S, T, A, B> lens, B b, S s) {
3335
return over(lens, constantly(b), s);
3436
}
3537

38+
@SuppressWarnings("unchecked")
3639
public static <S, T, A, B> Set<S, T, A, B> set() {
37-
return new Set<>();
40+
return INSTANCE;
3841
}
3942

4043
public static <S, T, A, B> Fn2<B, S, T> set(Lens<S, T, A, B> lens) {

src/main/java/com/jnape/palatable/lambda/lens/functions/View.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
*/
2121
public final class View<S, T, A, B> implements Fn2<Lens<S, T, A, B>, S, A> {
2222

23+
private static final View INSTANCE = new View();
24+
2325
private View() {
2426
}
2527

@@ -28,8 +30,9 @@ public A apply(Lens<S, T, A, B> lens, S s) {
2830
return lens.<Const<A, ?>, Const<A, T>, Const<A, B>>fix().apply(Const::new, s).runConst();
2931
}
3032

33+
@SuppressWarnings("unchecked")
3134
public static <S, T, A, B> View<S, T, A, B> view() {
32-
return new View<>();
35+
return INSTANCE;
3336
}
3437

3538
public static <S, T, A, B> Fn1<S, A> view(Lens<S, T, A, B> lens) {
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package com.jnape.palatable.lambda.monoid.builtin;
2+
3+
import com.jnape.palatable.lambda.functions.Fn1;
4+
import com.jnape.palatable.lambda.monoid.Monoid;
5+
6+
/**
7+
* A {@link Monoid} instance formed by <code>String</code> that concats two strings together.
8+
*
9+
* @see Monoid
10+
*/
11+
public final class Join implements Monoid<String> {
12+
13+
private static final Join INSTANCE = new Join();
14+
15+
private Join() {
16+
}
17+
18+
@Override
19+
public String identity() {
20+
return "";
21+
}
22+
23+
@Override
24+
public String apply(String x, String y) {
25+
return x + y;
26+
}
27+
28+
public static Join join() {
29+
return INSTANCE;
30+
}
31+
32+
public static Fn1<String, String> join(String x) {
33+
return join().apply(x);
34+
}
35+
36+
public static String join(String x, String y) {
37+
return join(x).apply(y);
38+
}
39+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.jnape.palatable.lambda.adt.hmap;
2+
3+
import org.junit.Test;
4+
5+
import static com.jnape.palatable.lambda.adt.hmap.TypeSafeKey.typeSafeKey;
6+
import static org.junit.Assert.assertFalse;
7+
8+
public class TypeSafeKeyTest {
9+
10+
@Test
11+
public void usesReferenceEquality() {
12+
assertFalse(typeSafeKey().equals(typeSafeKey()));
13+
}
14+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.jnape.palatable.lambda.functions.builtin.fn2;
2+
3+
import com.jnape.palatable.lambda.functions.Fn1;
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.EmptyIterableSupport;
9+
import testsupport.traits.FiniteIteration;
10+
import testsupport.traits.ImmutableIteration;
11+
import testsupport.traits.Laziness;
12+
13+
import static com.jnape.palatable.lambda.functions.builtin.fn2.Cons.cons;
14+
import static java.util.Arrays.asList;
15+
import static java.util.Collections.emptyList;
16+
import static org.junit.Assert.assertThat;
17+
import static testsupport.matchers.IterableMatcher.iterates;
18+
19+
@RunWith(Traits.class)
20+
public class ConsTest {
21+
22+
@TestTraits({Laziness.class, ImmutableIteration.class, FiniteIteration.class, EmptyIterableSupport.class})
23+
public Fn1<Iterable<Object>, Iterable<Object>> createTestSubject() {
24+
return cons(0);
25+
}
26+
27+
@Test
28+
public void consingElementToHeadOfIterable() {
29+
assertThat(cons(0, asList(1, 2, 3)), iterates(0, 1, 2, 3));
30+
}
31+
32+
@Test
33+
public void consingToEmptyIterable() {
34+
assertThat(cons("foo", emptyList()), iterates("foo"));
35+
}
36+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package com.jnape.palatable.lambda.iterators;
2+
3+
import org.junit.Before;
4+
import org.junit.Test;
5+
6+
import java.util.Collections;
7+
8+
import static com.jnape.palatable.lambda.functions.builtin.fn2.Drop.drop;
9+
import static com.jnape.palatable.lambda.functions.builtin.fn2.Iterate.iterate;
10+
import static com.jnape.palatable.lambda.functions.builtin.fn2.Take.take;
11+
import static com.jnape.palatable.lambda.functions.builtin.fn3.FoldRight.foldRight;
12+
import static java.util.Arrays.asList;
13+
import static org.junit.Assert.assertEquals;
14+
import static org.junit.Assert.assertFalse;
15+
import static org.junit.Assert.assertTrue;
16+
17+
public class ConsingIteratorTest {
18+
19+
private ConsingIterator<Integer> consingIterator;
20+
21+
@Before
22+
public void setUp() {
23+
consingIterator = new ConsingIterator<>(0, asList(1, 2, 3));
24+
}
25+
26+
@Test
27+
public void hasNextIfHeadNotYetIterated() {
28+
assertTrue(consingIterator.hasNext());
29+
}
30+
31+
@Test
32+
public void nextIsHeadIfNotYetIterated() {
33+
assertEquals((Integer) 0, consingIterator.next());
34+
}
35+
36+
@Test
37+
public void hasNextIfMoreElementsAfterHead() {
38+
consingIterator.next();
39+
assertTrue(consingIterator.hasNext());
40+
}
41+
42+
@Test
43+
public void doesNotHaveNextIfNoElementsLeft() {
44+
consingIterator.next();
45+
consingIterator.next();
46+
consingIterator.next();
47+
consingIterator.next();
48+
assertFalse(consingIterator.hasNext());
49+
}
50+
51+
@Test
52+
public void stackSafety() {
53+
Integer stackBlowingNumber = 1000000;
54+
Iterable<Integer> ints = foldRight((x, acc) -> () -> new ConsingIterator<>(x, acc),
55+
(Iterable<Integer>) Collections.<Integer>emptyList(),
56+
take(stackBlowingNumber, iterate(x -> x + 1, 1)));
57+
58+
assertEquals(stackBlowingNumber,
59+
take(1, drop(stackBlowingNumber - 1, ints)).iterator().next());
60+
}
61+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package com.jnape.palatable.lambda.monoid.builtin;
2+
3+
import org.junit.Test;
4+
5+
import static com.jnape.palatable.lambda.monoid.builtin.Join.join;
6+
import static org.junit.Assert.assertEquals;
7+
8+
public class JoinTest {
9+
10+
@Test
11+
public void identity() {
12+
assertEquals("", join().identity());
13+
}
14+
15+
@Test
16+
public void monoid() {
17+
assertEquals("ab", join().apply("a", "b"));
18+
assertEquals("a", join().apply("a", ""));
19+
assertEquals("b", join().apply("", "b"));
20+
assertEquals("", join().apply("", ""));
21+
}
22+
}

0 commit comments

Comments
 (0)