Skip to content

Commit 23bd94b

Browse files
committed
Initial Zipper implementation
1 parent 75baa5e commit 23bd94b

File tree

7 files changed

+283
-0
lines changed

7 files changed

+283
-0
lines changed
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package com.jnape.palatable.lambda.functions.builtin.fn1;
2+
3+
import com.jnape.palatable.lambda.adt.Maybe;
4+
import com.jnape.palatable.lambda.functions.Fn1;
5+
import com.jnape.palatable.lambda.traversable.Traversable;
6+
import com.jnape.palatable.lambda.zipper.Zipper;
7+
8+
import static com.jnape.palatable.lambda.adt.Maybe.just;
9+
import static com.jnape.palatable.lambda.adt.Maybe.nothing;
10+
import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly;
11+
12+
public final class Focus<A, TA extends Traversable<A, ?>> implements Fn1<Zipper<A, TA>, Maybe<A>> {
13+
14+
private static final Focus INSTANCE = new Focus();
15+
16+
private Focus() {
17+
}
18+
19+
@Override
20+
public Maybe<A> apply(Zipper<A, TA> zipper) {
21+
return zipper.match(constantly(nothing()), t -> just(t._1()));
22+
}
23+
24+
@SuppressWarnings("unchecked")
25+
public static <A, TA extends Traversable<A, ?>> Focus<A, TA> focus() {
26+
return INSTANCE;
27+
}
28+
29+
public static <A, TA extends Traversable<A, ?>> Maybe<A> focus(Zipper<A, TA> zipper) {
30+
return Focus.<A, TA>focus().apply(zipper);
31+
}
32+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.jnape.palatable.lambda.functions.builtin.fn1;
2+
3+
import com.jnape.palatable.lambda.functions.Fn1;
4+
import com.jnape.palatable.lambda.traversable.Traversable;
5+
import com.jnape.palatable.lambda.zipper.Zipper;
6+
7+
import static com.jnape.palatable.lambda.adt.Maybe.nothing;
8+
9+
public final class Next<A, TA extends Traversable<A, ?>> implements Fn1<Zipper<A, TA>, Zipper<A, TA>> {
10+
11+
private static final Next INSTANCE = new Next();
12+
13+
private Next() {
14+
}
15+
16+
@Override
17+
public Zipper<A, TA> apply(Zipper<A, TA> zipper) {
18+
return zipper.match(Zipper::top, n -> n._2().apply(nothing()));
19+
}
20+
21+
@SuppressWarnings("unchecked")
22+
public static <A, TA extends Traversable<A, ?>> Next<A, TA> next() {
23+
return INSTANCE;
24+
}
25+
26+
public static <A, TA extends Traversable<A, ?>> Zipper<A, TA> next(Zipper<A, TA> zipper) {
27+
return Next.<A, TA>next().apply(zipper);
28+
}
29+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.jnape.palatable.lambda.functions.builtin.fn1;
2+
3+
import com.jnape.palatable.lambda.functions.Fn1;
4+
import com.jnape.palatable.lambda.monad.builtin.Cont;
5+
6+
import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id;
7+
8+
public final class Reset<R> implements Fn1<Cont<R, R>, R> {
9+
10+
private static final Reset INSTANCE = new Reset<>();
11+
12+
private Reset() {
13+
}
14+
15+
@Override
16+
public R apply(Cont<R, R> cont) {
17+
return cont.runCont(id());
18+
}
19+
20+
@SuppressWarnings("unchecked")
21+
public static <R> Reset<R> reset() {
22+
return INSTANCE;
23+
}
24+
25+
public static <R> R reset(Cont<R, R> cont) {
26+
return Reset.<R>reset().apply(cont);
27+
}
28+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.jnape.palatable.lambda.functions.builtin.fn1;
2+
3+
import com.jnape.palatable.lambda.functions.Fn1;
4+
import com.jnape.palatable.lambda.monad.builtin.Cont;
5+
6+
import java.util.function.Function;
7+
8+
public final class Shift<A, R> implements Fn1<Function<? super Function<? super A, ? extends R>, Cont<R, R>>, Cont<R, A>> {
9+
10+
private static final Shift INSTANCE = new Shift();
11+
12+
private Shift() {
13+
}
14+
15+
@Override
16+
public Cont<R, A> apply(Function<? super Function<? super A, ? extends R>, Cont<R, R>> contFn) {
17+
return new Cont<>(k -> Reset.reset(contFn.apply(k)));
18+
}
19+
20+
@SuppressWarnings("unchecked")
21+
public static <A, R> Shift<A, R> shift() {
22+
return INSTANCE;
23+
}
24+
25+
public static <A, R> Cont<R, A> shift(Function<? super Function<? super A, ? extends R>, Cont<R, R>> contFn) {
26+
return Shift.<A, R>shift().apply(contFn);
27+
}
28+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package com.jnape.palatable.lambda.functions.builtin.fn1;
2+
3+
import com.jnape.palatable.lambda.functions.Fn1;
4+
import com.jnape.palatable.lambda.functions.recursion.RecursiveResult;
5+
import com.jnape.palatable.lambda.traversable.Traversable;
6+
import com.jnape.palatable.lambda.zipper.Zipper;
7+
8+
import static com.jnape.palatable.lambda.adt.Maybe.nothing;
9+
import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into;
10+
import static com.jnape.palatable.lambda.functions.recursion.RecursiveResult.recurse;
11+
import static com.jnape.palatable.lambda.functions.recursion.Trampoline.trampoline;
12+
13+
public final class ZipUp<A, TA extends Traversable<A, ?>> implements Fn1<Zipper<A, TA>, TA> {
14+
15+
private static final ZipUp INSTANCE = new ZipUp();
16+
17+
private ZipUp() {
18+
}
19+
20+
@Override
21+
public TA apply(Zipper<A, TA> zipper) {
22+
return trampoline(doneOrFocus -> doneOrFocus.match(RecursiveResult::terminate,
23+
into((__, focusFn) -> recurse(focusFn.apply(nothing())))),
24+
zipper);
25+
}
26+
27+
@SuppressWarnings("unchecked")
28+
public static <A, TA extends Traversable<A, ?>> ZipUp<A, TA> zipUp() {
29+
return INSTANCE;
30+
}
31+
32+
public static <A, TA extends Traversable<A, ?>> TA zipUp(Zipper<A, TA> zipper) {
33+
return ZipUp.<A, TA>zipUp().apply(zipper);
34+
}
35+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package com.jnape.palatable.lambda.monad.builtin;
2+
3+
import com.jnape.palatable.lambda.functions.Fn1;
4+
import com.jnape.palatable.lambda.functor.Applicative;
5+
import com.jnape.palatable.lambda.monad.Monad;
6+
7+
import java.util.function.Function;
8+
9+
public final class Cont<R, A> implements Monad<A, Cont<R, ?>> {
10+
private final Fn1<Function<? super A, ? extends R>, R> continuation;
11+
12+
public Cont(Fn1<Function<? super A, ? extends R>, R> continuation) {
13+
this.continuation = continuation;
14+
}
15+
16+
public R runCont(Function<? super A, ? extends R> fn) {
17+
return continuation.apply(fn);
18+
}
19+
20+
@Override
21+
public <B> Cont<R, B> fmap(Function<? super A, ? extends B> fn) {
22+
return Monad.super.<B>fmap(fn).coerce();
23+
}
24+
25+
@Override
26+
public <B> Cont<R, B> zip(Applicative<Function<? super A, ? extends B>, Cont<R, ?>> appFn) {
27+
return Monad.super.zip(appFn).coerce();
28+
}
29+
30+
@Override
31+
public <B> Cont<R, B> discardL(Applicative<B, Cont<R, ?>> appB) {
32+
return Monad.super.discardL(appB).coerce();
33+
}
34+
35+
@Override
36+
public <B> Cont<R, A> discardR(Applicative<B, Cont<R, ?>> appB) {
37+
return Monad.super.discardR(appB).coerce();
38+
}
39+
40+
@Override
41+
public <B> Cont<R, B> pure(B b) {
42+
return new Cont<>(f -> f.apply(b));
43+
}
44+
45+
@Override
46+
public <B> Cont<R, B> flatMap(Function<? super A, ? extends Monad<B, Cont<R, ?>>> f) {
47+
return new Cont<>(k -> runCont(f.<Cont<R, B>>andThen(Applicative::coerce).andThen(c -> c.runCont(k))));
48+
}
49+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package com.jnape.palatable.lambda.zipper;
2+
3+
import com.jnape.palatable.lambda.adt.Maybe;
4+
import com.jnape.palatable.lambda.adt.coproduct.CoProduct2;
5+
import com.jnape.palatable.lambda.adt.hlist.Tuple2;
6+
import com.jnape.palatable.lambda.functions.Fn1;
7+
import com.jnape.palatable.lambda.monad.builtin.Cont;
8+
import com.jnape.palatable.lambda.traversable.LambdaIterable;
9+
import com.jnape.palatable.lambda.traversable.Traversable;
10+
11+
import java.util.function.Function;
12+
13+
import static com.jnape.palatable.lambda.adt.hlist.HList.tuple;
14+
import static com.jnape.palatable.lambda.functions.Fn1.fn1;
15+
import static com.jnape.palatable.lambda.functions.builtin.fn1.Focus.focus;
16+
import static com.jnape.palatable.lambda.functions.builtin.fn1.Next.next;
17+
import static com.jnape.palatable.lambda.functions.builtin.fn1.Reset.reset;
18+
import static com.jnape.palatable.lambda.functions.builtin.fn1.Shift.shift;
19+
import static com.jnape.palatable.lambda.functions.builtin.fn2.Iterate.iterate;
20+
import static com.jnape.palatable.lambda.functions.builtin.fn2.Take.take;
21+
import static com.jnape.palatable.lambda.functions.builtin.fn3.Times.times;
22+
23+
public abstract class Zipper<A, TA extends Traversable<A, ?>>
24+
implements CoProduct2<TA, Tuple2<A, Function<Maybe<A>, Zipper<A, TA>>>, Zipper<A, TA>> {
25+
26+
private Zipper() {
27+
}
28+
29+
public static <A, T extends Traversable, TA extends Traversable<A, T>> Zipper<A, TA> zipper(TA ta) {
30+
return reset(ta.<A, Cont<Zipper<A, TA>, ?>, TA, Cont<Zipper<A, TA>, A>, Cont<Zipper<A, TA>, TA>>traverse(
31+
a -> shift(k -> new Cont<>(g -> g.apply(hole(a, maybeA -> k.apply(maybeA.orElse(a)))))),
32+
ta_ -> new Cont<>(g -> g.apply(ta_))).flatMap(trav -> new Cont<>(g -> g.apply(top(trav)))));
33+
}
34+
35+
public static <A, TA extends Traversable<A, ?>> Zipper<A, TA> top(TA ta) {
36+
return new Top<>(ta);
37+
}
38+
39+
public static <A, TA extends Traversable<A, ?>> Zipper<A, TA> hole(A a,
40+
Function<? super Maybe<A>, Zipper<A, TA>> nextFn) {
41+
return new Hole<>(a, fn1(nextFn));
42+
}
43+
44+
public static void main(String[] args) {
45+
Zipper<Integer, LambdaIterable<Integer>> zipper = zipper(LambdaIterable.wrap(take(100000, iterate(x -> x + 1, 0))));
46+
47+
System.out.println(focus(times(99_998, next(), zipper)));
48+
49+
System.out.println(focus(zipper));
50+
}
51+
52+
private static final class Top<A, TA extends Traversable<A, ?>> extends Zipper<A, TA> {
53+
private final TA ta;
54+
55+
private Top(TA ta) {
56+
this.ta = ta;
57+
}
58+
59+
@Override
60+
public <R> R match(Function<? super TA, ? extends R> aFn,
61+
Function<? super Tuple2<A, Function<Maybe<A>, Zipper<A, TA>>>, ? extends R> bFn) {
62+
return aFn.apply(ta);
63+
}
64+
}
65+
66+
private static final class Hole<A, TA extends Traversable<A, ?>> extends Zipper<A, TA> {
67+
private final A a;
68+
private final Fn1<Maybe<A>, Zipper<A, TA>> nextFn;
69+
70+
private Hole(A a, Fn1<Maybe<A>, Zipper<A, TA>> nextFn) {
71+
this.a = a;
72+
this.nextFn = nextFn;
73+
}
74+
75+
@Override
76+
public <R> R match(Function<? super TA, ? extends R> aFn,
77+
Function<? super Tuple2<A, Function<Maybe<A>, Zipper<A, TA>>>, ? extends R> bFn) {
78+
return bFn.apply(tuple(a, nextFn));
79+
}
80+
}
81+
82+
}

0 commit comments

Comments
 (0)