the second input argument type
* @param the third input argument type
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/$.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/$.java
new file mode 100644
index 000000000..63c60c051
--- /dev/null
+++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/$.java
@@ -0,0 +1,43 @@
+package com.jnape.palatable.lambda.functions.builtin.fn2;
+
+import com.jnape.palatable.lambda.functions.Fn1;
+import com.jnape.palatable.lambda.functions.Fn2;
+
+/**
+ * Function application, represented as a higher-order {@link Fn2} that receives an {@link Fn1} and its argument, and
+ * applies it. Useful for treating application as a combinator, e.g.:
+ *
+ * {@code
+ * List> fns = asList(x -> x + 1, x -> x, x -> x - 1);
+ * List args = asList(0, 1, 2);
+ * Iterable results = zipWith($(), fns, args); // [1, 1, 1]
+ * }
+ *
+ *
+ * @param the applied {@link Fn1 Fn1's} input type
+ * @param the applied {@link Fn1 Fn1's} output type
+ */
+public final class $ implements Fn2, A, B> {
+ private static final $, ?> INSTANCE = new $<>();
+
+ private $() {
+ }
+
+ @Override
+ public B checkedApply(Fn1 super A, ? extends B> fn, A a) {
+ return fn.apply(a);
+ }
+
+ @SuppressWarnings("unchecked")
+ public static $ $() {
+ return ($) INSTANCE;
+ }
+
+ public static Fn1 $(Fn1 super A, ? extends B> fn) {
+ return $.$().apply(fn);
+ }
+
+ public static B $(Fn1 super A, ? extends B> fn, A a) {
+ return $.$(fn).apply(a);
+ }
+}
diff --git a/src/main/java/com/jnape/palatable/lambda/internal/iteration/PredicatedDroppingIterable.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/PredicatedDroppingIterable.java
index d87cf0e09..ea7b68bc7 100644
--- a/src/main/java/com/jnape/palatable/lambda/internal/iteration/PredicatedDroppingIterable.java
+++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/PredicatedDroppingIterable.java
@@ -1,24 +1,20 @@
package com.jnape.palatable.lambda.internal.iteration;
import com.jnape.palatable.lambda.functions.Fn1;
+import com.jnape.palatable.lambda.internal.ImmutableQueue;
-import java.util.ArrayList;
import java.util.Iterator;
-import java.util.List;
-
-import static com.jnape.palatable.lambda.functions.builtin.fn2.Any.any;
-import static java.util.Collections.singletonList;
public final class PredicatedDroppingIterable implements Iterable {
- private final List> predicates;
- private final Iterable as;
+ private final ImmutableQueue> predicates;
+ private final Iterable as;
public PredicatedDroppingIterable(Fn1 super A, ? extends Boolean> predicate, Iterable as) {
- List> predicates = new ArrayList<>(singletonList(predicate));
+ ImmutableQueue> predicates = ImmutableQueue.singleton(predicate);
while (as instanceof PredicatedDroppingIterable) {
PredicatedDroppingIterable nested = (PredicatedDroppingIterable) as;
as = nested.as;
- predicates.addAll(0, nested.predicates);
+ predicates = nested.predicates.concat(predicates);
}
this.predicates = predicates;
this.as = as;
@@ -26,7 +22,6 @@ public PredicatedDroppingIterable(Fn1 super A, ? extends Boolean> predicate, I
@Override
public Iterator iterator() {
- Fn1 super A, ? extends Boolean> metaPredicate = a -> any(p -> p.apply(a), predicates);
- return new PredicatedDroppingIterator<>(metaPredicate, as.iterator());
+ return new PredicatedDroppingIterator<>(predicates, as.iterator());
}
}
diff --git a/src/main/java/com/jnape/palatable/lambda/internal/iteration/PredicatedDroppingIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/PredicatedDroppingIterator.java
index 7add62a45..a97b513ac 100644
--- a/src/main/java/com/jnape/palatable/lambda/internal/iteration/PredicatedDroppingIterator.java
+++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/PredicatedDroppingIterator.java
@@ -1,19 +1,18 @@
package com.jnape.palatable.lambda.internal.iteration;
import com.jnape.palatable.lambda.functions.Fn1;
+import com.jnape.palatable.lambda.internal.ImmutableQueue;
import java.util.Iterator;
import java.util.NoSuchElementException;
public final class PredicatedDroppingIterator extends ImmutableIterator {
- private final Fn1 super A, ? extends Boolean> predicate;
- private final RewindableIterator rewindableIterator;
- private boolean finishedDropping;
+ private final Iterator> predicates;
+ private final RewindableIterator rewindableIterator;
- public PredicatedDroppingIterator(Fn1 super A, ? extends Boolean> predicate, Iterator asIterator) {
- this.predicate = predicate;
+ public PredicatedDroppingIterator(ImmutableQueue> predicates, Iterator asIterator) {
+ this.predicates = predicates.iterator();
rewindableIterator = new RewindableIterator<>(asIterator);
- finishedDropping = false;
}
@Override
@@ -31,11 +30,17 @@ public A next() {
}
private void dropElementsIfNecessary() {
- while (rewindableIterator.hasNext() && !finishedDropping) {
- if (!predicate.apply(rewindableIterator.next())) {
- rewindableIterator.rewind();
- finishedDropping = true;
+ while (predicates.hasNext() && rewindableIterator.hasNext()) {
+ Fn1 super A, ? extends Boolean> predicate = predicates.next();
+ boolean predicateDone = false;
+
+ while (rewindableIterator.hasNext() && !predicateDone) {
+ if (!predicate.apply(rewindableIterator.next())) {
+ rewindableIterator.rewind();
+ predicateDone = true;
+ }
}
+
}
}
}
diff --git a/src/main/java/com/jnape/palatable/lambda/internal/iteration/RewindableIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/RewindableIterator.java
index 5bdde4312..092e7e98b 100644
--- a/src/main/java/com/jnape/palatable/lambda/internal/iteration/RewindableIterator.java
+++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/RewindableIterator.java
@@ -54,9 +54,7 @@ public A retrieve() {
if (cache == null)
throw new NoSuchElementException("Cache is empty.");
- A cache = this.cache;
- this.cache = null;
- return cache;
+ return this.cache;
}
public boolean isEmpty() {
diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateT.java
index 606e7d894..cb719060b 100644
--- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateT.java
+++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateT.java
@@ -8,6 +8,7 @@
import com.jnape.palatable.lambda.functions.Fn1;
import com.jnape.palatable.lambda.functions.Fn2;
import com.jnape.palatable.lambda.functions.recursion.RecursiveResult;
+import com.jnape.palatable.lambda.functions.specialized.Lift;
import com.jnape.palatable.lambda.functions.specialized.Pure;
import com.jnape.palatable.lambda.functor.Applicative;
import com.jnape.palatable.lambda.functor.builtin.Lazy;
@@ -28,6 +29,9 @@
import static com.jnape.palatable.lambda.adt.choice.Choice2.a;
import static com.jnape.palatable.lambda.adt.choice.Choice2.b;
import static com.jnape.palatable.lambda.adt.hlist.HList.tuple;
+import static com.jnape.palatable.lambda.functions.Fn0.fn0;
+import static com.jnape.palatable.lambda.functions.Fn1.withSelf;
+import static com.jnape.palatable.lambda.functions.builtin.fn2.$.$;
import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into;
import static com.jnape.palatable.lambda.functions.builtin.fn2.Tupler2.tupler;
import static com.jnape.palatable.lambda.functions.builtin.fn3.FoldLeft.foldLeft;
@@ -61,22 +65,15 @@
* @param the effect type
* @param the element type
*/
-public class IterateT, A> implements
- MonadT, IterateT, ?>> {
+public class IterateT, A> implements MonadT, IterateT, ?>> {
private final Pure pureM;
- private final ImmutableQueue> conses;
- private final ImmutableQueue>>, M>>, IterateT>> middles;
- private final ImmutableQueue> snocs;
+ private final ImmutableQueue>>, M>>, MonadRec>> spine;
private IterateT(Pure pureM,
- ImmutableQueue> conses,
- ImmutableQueue>>, M>>, IterateT>> middles,
- ImmutableQueue> snocs) {
+ ImmutableQueue>>, M>>, MonadRec>> spine) {
this.pureM = pureM;
- this.conses = conses;
- this.middles = middles;
- this.snocs = snocs;
+ this.spine = spine;
}
/**
@@ -86,7 +83,35 @@ private IterateT(Pure pureM,
* @return the embedded {@link Monad}
*/
public >>, M>> MMTA runIterateT() {
- return pureM., MonadRec, M>>apply(this).trampolineM(IterateT::resume).coerce();
+ return pureM., MonadRec, M>>apply(this)
+ .>>>trampolineM(iterateT -> iterateT.runStep()
+ .fmap(maybeMore -> maybeMore.match(
+ fn0(() -> terminate(nothing())),
+ t -> t.into((Maybe maybeA, IterateT as) -> maybeA.match(
+ fn0(() -> recurse(as)),
+ a -> terminate(just(tuple(a, as))))))))
+ .coerce();
+ }
+
+ /**
+ * Run a single step of this {@link IterateT}, where a step is the smallest amount of work that could possibly be
+ * productive in advancing through the {@link IterateT}. Useful for implementing interleaving algorithms that
+ * require {@link IterateT IterateTs} to yield, emit, or terminate as soon as possible, regardless of whether the
+ * next element is readily available.
+ *
+ * @param the witnessed target type of the step
+ * @return the step
+ */
+ public , IterateT>>, M>> MStep runStep() {
+ return spine.head().match(
+ fn0(() -> pureM., IterateT>>, MStep>apply(nothing())),
+ thunkOrReal -> thunkOrReal.match(
+ thunk -> thunk.apply()., IterateT>>>fmap(m -> m.match(
+ fn0(() -> just(tuple(nothing(), new IterateT<>(pureM, spine.tail())))),
+ t -> just(t.biMap(Maybe::just,
+ as -> new IterateT<>(pureM, as.spine.concat(spine.tail()))))))
+ .coerce(),
+ ma -> ma.fmap(a -> just(tuple(just(a), new IterateT<>(pureM, spine.tail())))).coerce()));
}
/**
@@ -96,7 +121,7 @@ public >>, M>> MMTA runIter
* @return the cons'ed {@link IterateT}
*/
public final IterateT cons(MonadRec head) {
- return new IterateT<>(pureM, conses.pushFront(head), middles, snocs);
+ return new IterateT<>(pureM, spine.pushFront(b(head)));
}
/**
@@ -106,7 +131,7 @@ public final IterateT cons(MonadRec head) {
* @return the snoc'ed {@link IterateT}
*/
public final IterateT snoc(MonadRec last) {
- return new IterateT<>(pureM, conses, middles, snocs.pushBack(last));
+ return new IterateT<>(pureM, spine.pushBack(b(last)));
}
/**
@@ -116,13 +141,7 @@ public final IterateT snoc(MonadRec last) {
* @return the concatenated {@link IterateT}
*/
public IterateT concat(IterateT other) {
- return new IterateT<>(pureM,
- conses,
- middles.pushBack(b(new IterateT<>(pureM,
- snocs.concat(other.conses),
- other.middles,
- other.snocs))),
- ImmutableQueue.empty());
+ return new IterateT<>(pureM, spine.concat(other.spine));
}
/**
@@ -188,9 +207,19 @@ public > IterateT lift(MonadRec nb) {
* {@inheritDoc}
*/
@Override
+ @SuppressWarnings("RedundantTypeArguments")
public IterateT trampolineM(
Fn1 super A, ? extends MonadRec, IterateT>> fn) {
- return trampolineM(fn, ImmutableQueue.>>empty().pushBack(flatMap(fn)));
+ return $(withSelf(
+ (self, queued) -> suspended(
+ () -> pureM.>, MonadRec>, M>>apply(queued)
+ .trampolineM(q -> q.runIterateT().>, Maybe>>>>fmap(m -> m.match(
+ __ -> terminate(nothing()),
+ into((rr, tail) -> rr.biMap(
+ a -> fn.apply(a).>>coerce().concat(tail),
+ b -> just(tuple(b, self.apply(tail)))))))),
+ pureM)),
+ flatMap(fn));
}
/**
@@ -199,11 +228,15 @@ public IterateT trampolineM(
@Override
public IterateT flatMap(Fn1 super A, ? extends Monad>> f) {
return suspended(() -> maybeT(runIterateT())
- .flatMap(into((a, as) -> maybeT(f.apply(a)
- .>coerce()
- .concat(as.flatMap(f))
- .runIterateT())))
- .runMaybeT(), pureM);
+ .trampolineM(into((a, as) -> maybeT(
+ f.apply(a).>coerce().runIterateT()
+ .flatMap(maybePair -> maybePair.match(
+ fn0(() -> as.runIterateT()
+ .fmap(maybeResult -> maybeResult.fmap(RecursiveResult::recurse))),
+ t -> pureM.apply(just(terminate(t.fmap(mb -> mb.concat(as.flatMap(f))))))
+ )))))
+ .runMaybeT(),
+ pureM);
}
/**
@@ -219,7 +252,7 @@ public IterateT fmap(Fn1 super A, ? extends B> fn) {
*/
@Override
public IterateT pure(B b) {
- return singleton(runIterateT().pure(b));
+ return singleton(pureM.>apply(b));
}
/**
@@ -286,54 +319,6 @@ public IterateT discardR(Applicative> appB) {
return MonadT.super.discardR(appB).coerce();
}
- private MonadRec, Maybe>>>, M> resume() {
- return conses.head().match(
- __ -> middles.head().match(
- ___ -> snocs.head().match(
- ____ -> pureM.apply(terminate(nothing())),
- ma -> ma.fmap(a -> terminate(just(tuple(a, new IterateT<>(pureM,
- snocs.tail(),
- ImmutableQueue.empty(),
- ImmutableQueue.empty())))))),
- lazyOrStrict -> lazyOrStrict.match(
- lazy -> lazy.apply().fmap(maybeRes -> maybeRes.match(
- ___ -> recurse(new IterateT<>(pureM, ImmutableQueue.empty(), middles.tail(), snocs)),
- into((a, as) -> recurse(new IterateT<>(pureM,
- ImmutableQueue.singleton(pureM.apply(a)),
- ImmutableQueue.singleton(b(migrateForward(as))),
- ImmutableQueue.empty())))
- )),
- strict -> pureM.apply(recurse(migrateForward(strict))))),
- ma -> ma.fmap(a -> terminate(just(tuple(a, new IterateT<>(pureM, conses.tail(), middles, snocs))))));
- }
-
- private IterateT migrateForward(IterateT as) {
- if (middles.tail().isEmpty()) {
- return new IterateT<>(pureM, conses.concat(as.conses), as.middles, as.snocs.concat(snocs));
- }
-
- IterateT lasts = new IterateT<>(pureM, as.snocs, middles.tail(), snocs);
- return new IterateT<>(pureM, as.conses, as.middles.pushBack(b(lasts)), ImmutableQueue.empty());
- }
-
- private IterateT trampolineM(Fn1 super A, ? extends MonadRec, IterateT>> fn,
- ImmutableQueue>> queued) {
- return suspended(() -> {
- MonadRec>>, M> pureQueue = pureM.apply(queued);
- return pureQueue.trampolineM(
- q -> q.head().match(
- __ -> pureM.apply(terminate(nothing())),
- next -> next.runIterateT().flatMap(maybeMore -> maybeMore.match(
- __ -> pureM.apply(terminate(nothing())),
- t -> t.into((aOrB, rest) -> aOrB.match(
- a -> pureM.apply(recurse(q.pushFront(fn.apply(a).coerce()))),
- b -> trampolineM(fn, q.tail().pushFront(rest))
- .cons(pureM.apply(b))
- .runIterateT()
- .fmap(RecursiveResult::terminate)))))));
- }, pureM);
- }
-
/**
* Static factory method for creating an empty {@link IterateT}.
*
@@ -343,7 +328,7 @@ private IterateT trampolineM(Fn1 super A, ? extends MonadRec, A> IterateT empty(Pure pureM) {
- return new IterateT<>(pureM, ImmutableQueue.empty(), ImmutableQueue.empty(), ImmutableQueue.empty());
+ return new IterateT<>(pureM, ImmutableQueue.empty());
}
/**
@@ -355,10 +340,7 @@ public static , A> IterateT empty(Pure pureM)
* @return the singleton {@link IterateT}
*/
public static , A> IterateT singleton(MonadRec ma) {
- return new IterateT<>(Pure.of(ma),
- ImmutableQueue.>empty().pushFront(ma),
- ImmutableQueue.empty(),
- ImmutableQueue.empty());
+ return IterateT.empty(Pure.of(ma)).cons(ma);
}
/**
@@ -371,12 +353,7 @@ public static , A> IterateT singleton(MonadRec, A> IterateT iterateT(
MonadRec>>, M> unwrapped) {
- return new IterateT<>(
- Pure.of(unwrapped),
- ImmutableQueue.empty(),
- ImmutableQueue.>>, M>>, IterateT>>empty()
- .pushFront(a(() -> unwrapped)),
- ImmutableQueue.empty());
+ return suspended(() -> unwrapped, Pure.of(unwrapped));
}
/**
@@ -393,9 +370,7 @@ public static , A> IterateT of(
MonadRec ma, MonadRec... mas) {
@SuppressWarnings("varargs")
List> as = asList(mas);
- return foldLeft(IterateT::snoc,
- empty(Pure.of(ma)),
- com.jnape.palatable.lambda.functions.builtin.fn2.Cons.cons(ma, as));
+ return foldLeft(IterateT::snoc, singleton(ma), as);
}
/**
@@ -412,9 +387,10 @@ public static , A> IterateT of(
*/
public static , A, B> IterateT unfold(
Fn1 super B, ? extends MonadRec>, M>> fn, MonadRec mb) {
- return suspended(() -> maybeT(mb.flatMap(fn))
- .fmap(ab -> ab.fmap(b -> unfold(fn, mb.pure(b))))
- .runMaybeT(), Pure.of(mb));
+ Pure pureM = Pure.of(mb);
+ return $(withSelf((self, mmb) -> suspended(() -> maybeT(mmb.flatMap(fn))
+ .fmap(ab -> ab.>fmap(b -> self.apply(pureM.apply(b))))
+ .runMaybeT(), pureM)), mb);
}
/**
@@ -429,12 +405,7 @@ public static , A, B> IterateT unfold(
*/
public static , A> IterateT suspended(
Fn0>>, M>> thunk, Pure pureM) {
- return new IterateT<>(pureM,
- ImmutableQueue.empty(),
- ImmutableQueue
- .>>, M>>, IterateT>>empty()
- .pushFront(a(thunk)),
- ImmutableQueue.empty());
+ return new IterateT<>(pureM, ImmutableQueue.singleton(a(thunk)));
}
/**
@@ -451,4 +422,29 @@ public static IterateT, A> fromIterator(Iterator as) {
return nothing();
}), io(() -> as));
}
+
+ /**
+ * The canonical {@link Pure} instance for {@link IterateT}.
+ *
+ * @param pureM the argument {@link Monad} {@link Pure}
+ * @param the argument {@link Monad} witness
+ * @return the {@link Pure} instance
+ */
+ public static > Pure> pureIterateT(Pure pureM) {
+ return new Pure>() {
+ @Override
+ public IterateT checkedApply(A a) {
+ return liftIterateT().apply(pureM.>apply(a));
+ }
+ };
+ }
+
+ /**
+ * {@link Lift} for {@link IterateT}.
+ *
+ * @return the {@link Monad} lifted into {@link IterateT}
+ */
+ public static Lift> liftIterateT() {
+ return IterateT::singleton;
+ }
}
diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java
index c2e02fd94..95dcdfd21 100644
--- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java
+++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java
@@ -1,6 +1,7 @@
package com.jnape.palatable.lambda.monad.transformer.builtin;
import com.jnape.palatable.lambda.adt.Maybe;
+import com.jnape.palatable.lambda.adt.Unit;
import com.jnape.palatable.lambda.functions.Fn1;
import com.jnape.palatable.lambda.functions.recursion.RecursiveResult;
import com.jnape.palatable.lambda.functions.specialized.Lift;
@@ -9,6 +10,7 @@
import com.jnape.palatable.lambda.functor.builtin.Compose;
import com.jnape.palatable.lambda.functor.builtin.Lazy;
import com.jnape.palatable.lambda.monad.Monad;
+import com.jnape.palatable.lambda.monad.MonadError;
import com.jnape.palatable.lambda.monad.MonadRec;
import com.jnape.palatable.lambda.monad.transformer.MonadT;
@@ -16,6 +18,8 @@
import static com.jnape.palatable.lambda.adt.Maybe.just;
import static com.jnape.palatable.lambda.adt.Maybe.nothing;
+import static com.jnape.palatable.lambda.adt.Unit.UNIT;
+import static com.jnape.palatable.lambda.functions.Fn0.fn0;
import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly;
import static com.jnape.palatable.lambda.functions.recursion.RecursiveResult.terminate;
@@ -26,7 +30,7 @@
* @param the carrier type
*/
public final class MaybeT, A> implements
- MonadT, MaybeT, ?>> {
+ MonadT, MaybeT, ?>>, MonadError> {
private final MonadRec, M> mma;
@@ -67,6 +71,24 @@ public MaybeT or(MaybeT other) {
a -> mMaybeA.pure(just(a)))));
}
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public MaybeT throwError(Unit unit) {
+ return maybeT(mma.pure(nothing()));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public MaybeT catchError(Fn1 super Unit, ? extends Monad>> recoveryFn) {
+ return maybeT(mma.flatMap(maybeA -> maybeA.match(
+ fn0(() -> recoveryFn.apply(UNIT).>coerce().runMaybeT()),
+ a -> mma.pure(just(a)))));
+ }
+
/**
* {@inheritDoc}
*/
diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderT.java
index 443470c6e..e4c8ec5f0 100644
--- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderT.java
+++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderT.java
@@ -120,7 +120,7 @@ public ReaderT pure(B b) {
*/
@Override
public ReaderT fmap(Fn1 super A, ? extends B> fn) {
- return MonadT.super.fmap(fn).coerce();
+ return readerT(r -> runReaderT(r).fmap(fn));
}
/**
@@ -204,6 +204,19 @@ public ReaderT> carry() {
return (ReaderT>) Cartesian.super.carry();
}
+ /**
+ * Given a {@link Pure} ask will give you access to the input within the monadic embedding
+ *
+ * @param pureM the {@link Pure} instance for the given {@link Monad}
+ * @param the input and output type of the returned ReaderT
+ * @param the returned {@link Monad}
+ * @return the {@link ReaderT}
+ */
+ public static > ReaderT ask(Pure pureM) {
+ //noinspection Convert2MethodRef
+ return readerT(a -> pureM.apply(a));
+ }
+
/**
* Lift a {@link Fn1 function} (R -> {@link Monad}<A, M>) into a {@link ReaderT} instance.
*
diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/StateT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/StateT.java
index 071ce0dc5..219ad3e03 100644
--- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/StateT.java
+++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/StateT.java
@@ -144,7 +144,7 @@ public StateT pure(B b) {
*/
@Override
public StateT fmap(Fn1 super A, ? extends B> fn) {
- return MonadT.super.fmap(fn).coerce();
+ return stateT(s -> runStateT(s).fmap(t -> t.biMapL(fn)));
}
/**
@@ -292,7 +292,7 @@ public static , A> StateT stateT(
public static > Pure> pureStateT(Pure pureM) {
return new Pure>() {
@Override
- public StateT checkedApply(A a) throws Throwable {
+ public StateT checkedApply(A a) {
return stateT(pureM.>apply(a));
}
};
diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/WriterT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/WriterT.java
index 7a0205543..c8625bbf8 100644
--- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/WriterT.java
+++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/WriterT.java
@@ -34,9 +34,12 @@ public final class WriterT, A> implements
MonadWriter>,
MonadT, WriterT> {
+ private final Pure pureM;
private final Fn1 super Monoid, ? extends MonadRec, M>> writerFn;
- private WriterT(Fn1 super Monoid, ? extends MonadRec, M>> writerFn) {
+ private WriterT(Pure pureM,
+ Fn1 super Monoid, ? extends MonadRec, M>> writerFn) {
+ this.pureM = pureM;
this.writerFn = writerFn;
}
@@ -82,7 +85,7 @@ public > MW execWriterT(Monoid