From 4d9f164161c606f62b3f49442ae77cbf60d2d7b0 Mon Sep 17 00:00:00 2001 From: John McClean Date: Fri, 3 Feb 2017 23:40:26 +0000 Subject: [PATCH 01/14] kleisli --- src/main/java/cyclops/monads/Kleisli.java | 67 +++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 src/main/java/cyclops/monads/Kleisli.java diff --git a/src/main/java/cyclops/monads/Kleisli.java b/src/main/java/cyclops/monads/Kleisli.java new file mode 100644 index 0000000000..e4b6fcda69 --- /dev/null +++ b/src/main/java/cyclops/monads/Kleisli.java @@ -0,0 +1,67 @@ +package cyclops.monads; + + +import com.aol.cyclops2.types.Transformable; +import cyclops.control.either.Either; +import cyclops.function.Fn1; +import lombok.AllArgsConstructor; + +import java.util.function.Function; + +@AllArgsConstructor +public class Kleisli> implements Fn1>, + Transformable{ + + public final Fn1> fn; + + @Override + public AnyM apply(T a) { + + return fn.apply(a); + } + + public Kleisli map(Function mapper){ + return kliesli(fn.andThen(am->am.map(mapper))); + } + + public Kleisli flatMap(Function> mapper){ + return kliesli(fn.andThen(am->am.flatMapA(mapper))); + } + + public Kleisli compose(Kleisli kleisli) { + return new Kleisli(a -> kleisli.apply(a).flatMapA(this)); + } + public Kleisli then(Kleisli kleisli) { + + return new Kleisli(t->this.apply(t) + .flatMapA(kleisli)); + + } + + public Kleisli, Either,W> merge(Kleisli merge, W type) { + Kleisli, W> first = then(lift(Either::left, type)); + Kleisli, W> second = merge.then(lift(Either::right, type)); + return first.fanIn(second); + + } + + public Kleisli, R,W> fanIn(Kleisli fanIn) { + return new Kleisli<>(e -> e.visit(this, fanIn)); + } + + + + private static > Kleisli kliesli(Function> fn){ + return new Kleisli(narrow(fn)); + } + private static > Kleisli lift(Function fn, W type){ + return kliesli(fn.andThen(r->type.adapter().unit(r))); + } + + private static , R> Fn1> narrow(Function> fn) { + if(fn instanceof Fn1){ + return (Fn1)fn; + } + return in -> (AnyM)fn.apply(in); + } +} From 523d5166afd7f09bf0382fadbf162a2d6444e1f1 Mon Sep 17 00:00:00 2001 From: John McClean Date: Sat, 4 Feb 2017 21:58:02 +0000 Subject: [PATCH 02/14] more work on kleisli --- src/main/java/cyclops/control/Xor.java | 7 - src/main/java/cyclops/function/Fn1.java | 56 ++ src/main/java/cyclops/monads/AnyM2.java | 671 ++++++++++++++++++++ src/main/java/cyclops/monads/Cokleisli.java | 46 ++ src/main/java/cyclops/monads/Kleisli.java | 40 +- 5 files changed, 802 insertions(+), 18 deletions(-) create mode 100644 src/main/java/cyclops/monads/AnyM2.java create mode 100644 src/main/java/cyclops/monads/Cokleisli.java diff --git a/src/main/java/cyclops/control/Xor.java b/src/main/java/cyclops/control/Xor.java index 9dc91bf4c8..72afa540af 100644 --- a/src/main/java/cyclops/control/Xor.java +++ b/src/main/java/cyclops/control/Xor.java @@ -754,13 +754,6 @@ public static Xor accumulateSecondary(final Monoid reducer,f */ R visit(Function secondary, Function primary); - @Deprecated //use bimap instead - default Xor mapBoth(final Function secondary, final Function primary) { - if (isSecondary()) - return (Xor) swap().map(secondary) - .swap(); - return (Xor) map(primary); - } /* (non-Javadoc) * @see com.aol.cyclops2.types.BiFunctor#bimap(java.util.function.Function, java.util.function.Function) diff --git a/src/main/java/cyclops/function/Fn1.java b/src/main/java/cyclops/function/Fn1.java index 2a65aa593f..326e027a01 100644 --- a/src/main/java/cyclops/function/Fn1.java +++ b/src/main/java/cyclops/function/Fn1.java @@ -5,6 +5,8 @@ import java.util.function.Function; import cyclops.control.*; +import cyclops.control.either.Either; +import cyclops.monads.Kleisli; import cyclops.monads.transformers.FutureT; import cyclops.monads.transformers.ListT; import cyclops.collections.immutable.PStackX; @@ -20,6 +22,8 @@ import org.jooq.lambda.function.Function1; import org.jooq.lambda.tuple.Tuple; import org.jooq.lambda.tuple.Tuple2; +import org.jooq.lambda.tuple.Tuple3; +import org.jooq.lambda.tuple.Tuple4; @FunctionalInterface public interface Fn1 extends Function1 { @@ -62,10 +66,51 @@ default Fn1 memoize(Cacheable c){ return Memoize.memoizeFunction(this,c); } + default Fn1, Xor> merge(Function fn) { + Fn1> first = andThen(Either::left); + Function> second = fn.andThen(Either::right); + return first.fanIn(second); + + } + + default Fn1, R> fanIn(Function fanIn) { + return e -> e.visit(this, fanIn); + } + default <__> Fn1, Xor> left() { + + return either -> either.bimap(this,Function.identity()); + } + default <__> Fn1, Xor<__,R>> right() { + + return either -> either.bimap(Function.identity(),this); + } + + default Fn1> product(Fn1 fn){ return in -> Tuple.tuple(apply(in),fn.apply(in)); } + default <__> Fn1, Tuple2> first() { + + return t-> Tuple.tuple(apply(t.v1),t.v2); + } + default <__> Fn1, Tuple2<__, R>> second() { + + return t-> Tuple.tuple(t.v1,apply(t.v2)); + } + + + + + default Fn1> product(Function fn2, Function fn3) { + return a -> Tuple.tuple(apply(a), fn2.apply(a),fn3.apply(a)); + } + default Fn1> product(Function fn2, + Function fn3, + Function fn4) { + return a -> Tuple.tuple(apply(a), fn2.apply(a),fn3.apply(a),fn4.apply(a)); + } + default Fn0 bind(final T1 s) { return Curry.curry(this) @@ -88,6 +133,12 @@ default Fn1 andThen(Function after) { + static Fn1 narrow(Function fn){ + if(fn instanceof Fn1){ + return (Fn1)fn; + } + return t->fn.apply(t); + } default FunctionalOperations functionOps(){ return in->apply(in); } @@ -110,6 +161,11 @@ default Fn1 coflatMap(final Function f.apply(this); } + + + + + default > AnyM mapF(AnyM functor) { return functor.map(this); } diff --git a/src/main/java/cyclops/monads/AnyM2.java b/src/main/java/cyclops/monads/AnyM2.java new file mode 100644 index 0000000000..da3803f5f3 --- /dev/null +++ b/src/main/java/cyclops/monads/AnyM2.java @@ -0,0 +1,671 @@ +package cyclops.monads; + +import com.aol.cyclops2.data.collections.extensions.CollectionX; +import com.aol.cyclops2.data.collections.extensions.FluentSequenceX; +import com.aol.cyclops2.internal.monads.AnyMSeqImpl; +import com.aol.cyclops2.internal.monads.AnyMValueImpl; +import com.aol.cyclops2.types.*; +import com.aol.cyclops2.types.anyM.AnyMSeq; +import com.aol.cyclops2.types.anyM.AnyMValue; +import com.aol.cyclops2.types.extensability.FunctionalAdapter; +import com.aol.cyclops2.types.stream.ToStream; +import cyclops.Optionals; +import cyclops.Streams; +import cyclops.async.Future; +import cyclops.collections.ListX; +import cyclops.collections.SetX; +import cyclops.control.*; +import cyclops.control.either.Either; +import cyclops.control.either.Either3; +import cyclops.control.either.Either4; +import cyclops.control.either.Either5; +import cyclops.function.*; +import cyclops.monads.Witness.*; +import cyclops.monads.transformers.FutureT; +import cyclops.monads.transformers.ListT; +import cyclops.stream.FutureStream; +import cyclops.stream.ReactiveSeq; +import cyclops.stream.Streamable; +import org.jooq.lambda.function.Function3; +import org.jooq.lambda.function.Function4; +import org.jooq.lambda.function.Function5; +import org.jooq.lambda.tuple.Tuple2; +import org.jooq.lambda.tuple.Tuple3; +import org.jooq.lambda.tuple.Tuple4; +import org.reactivestreams.Publisher; + +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import java.util.function.*; +import java.util.stream.*; + +/** + * + * Wrapper for Any Monad type + * + * There are two subsclass of AnyM - @see {@link AnyMValue} and @see {@link AnyMSeq}. + * AnyMValue is used to represent Monads that wrap a single value such as {@link Optional}, {@link CompletableFuture}, {@link Maybe}, {@link Eval}, {@link Xor}, {@link Try}, {@link Ior}, {@link FeatureToggle} + * AnyMSeq is used to represent Monads that wrap an aggregation of values such as {@link Stream}, {@link FutureStream}, {@link List}, {@link Set}, {@link Streamable} + * + * Use AnyM to create your monad wrapper. + * AnyM.fromXXXX methods can create the appropriate AnyM type for a range of known monad types. + * + *
+ * {@code 
+ *    AnyMValue monad1 = AnyM.fromOptional(Optional.of("hello"));
+ *    
+ *    AnyMSeq monad2 = AnyM.fromStream(Stream.of("hello","world"));
+ *  
+ * }
+ * 
+ * + * Wrapped monads can be unwrapped via the unwrap method, or converted to the desired type via toXXXX methods + * + * + * + * @author johnmcclean + * + * @param type data wrapped by the underlying monad + */ +public interface AnyM2,T,T2> extends AnyM, + Unwrapable, + // To>, + EmptyUnit, + Unit, + Folds, + Transformable, + ToStream, + Zippable, + Publisher { + @Override + default ReactiveSeq reactiveSeq() { + return Streams.oneShotStream(StreamSupport.stream(this.spliterator(),false)); + } + + /** + * Collect the contents of the monad wrapped by this AnyM into supplied collector + * A mutable reduction operation equivalent to Stream#collect + * + *
+     * {@code
+     *      AnyM monad1 = AnyM.fromStream(Stream.of(1,2,3));
+     *      AnyM monad2 = AnyM.fromOptional(Optional.of(1));
+     *
+     *      List list1 = monad1.collect(Collectors.toList());
+     *      List list2 = monad2.collect(Collectors.toList());
+     *
+     * }
+     * 
+ * + * + * @param collector JDK collector to perform mutable reduction + * @return Reduced value + */ + default R collect(Collector collector){ + return this.stream().collect(collector); + } + @Override + default Iterator iterator() { + + return adapter().toIterable(this).iterator(); + + } + + default AnyMSeq unitIterator(Iterator U){ + return (AnyMSeq)adapter().unitIterable(()->U); + } + + AnyM2 flatMapI(Function> fn); + AnyM2 flatMapP(Function> fn); + AnyM2 flatMapS(Function> fn); + default AnyM2 flatMapA(Function> fn){ + return adapter().flatMap(this, fn); + } + default AnyM2 map(Function fn){ + return adapter().map(this, fn); + } + default AnyM2 fromIterable(Iterable t){ + return (AnyM2)adapter().unitIterable(t); + } + + @Override + default AnyM2 zipWith(Iterable> fn) { + return (AnyM2)AnyM.super.zipWith(fn); + } + + @Override + default AnyM2 zipWithS(Stream> fn) { + return (AnyM2)AnyM.super.zipWithS(fn); + } + + @Override + default AnyM2 zipWithP(Publisher> fn) { + return (AnyM2)AnyM.super.zipWithP(fn); + } + + @Override + default AnyM2 retry(final Function fn) { + return (AnyM2)AnyM.super.retry(fn); + } + + @Override + default AnyM2,T2> zipP(final Publisher other) { + return (AnyM2)AnyM.super.zipP(other); + } + + @Override + default AnyM2 retry(final Function fn, final int retries, final long delay, final TimeUnit timeUnit) { + return (AnyM2)AnyM.super.retry(fn,retries,delay,timeUnit); + } + + @Override + default AnyM2,T2> zip3(final Iterable second, final Iterable third) { + return (AnyM2)AnyM.super.zip3(second,third); + } + + @Override + default AnyM2 zip3(final Iterable second, final Iterable third, final Fn3 fn3) { + return (AnyM2)AnyM.super.zip3(second,third,fn3); + } + + @Override + default AnyM2,T2> zip4(final Iterable second, final Iterable third, final Iterable fourth) { + return (AnyM2)AnyM.super.zip4(second,third,fourth); + } + + @Override + default AnyM2 zip4(final Iterable second, final Iterable third, final Iterable fourth, final Fn4 fn) { + return (AnyM2)AnyM.super.zip4(second,third,fourth,fn); + } + + + /** + * Construct a new instanceof AnyM using the type of the underlying wrapped monad + * + *
+     * {@code
+     *   AnyM ints = AnyM.fromList(Arrays.asList(1,2,3);
+     *   AnyM string = ints.unit("hello");
+     * }
+     * 
+ * + * @param t to embed inside the monad wrapped by AnyM + * @return Newly instantated AnyM + */ + @Override + default AnyM2 unit(T t){ + return adapter().unit(t); + } + + /** + * Applicative 'ap' method to use fluently + * + *
+     * {@code 
+     *    AnyM> add = AnyM.fromNullable(this::add2);
+     *    add.to(AnyM::ap)
+     *       .apply(AnyM.ofNullable(10));
+     *   
+     *    //AnyM[12] //add 2
+     * 
+     * }
+     * 
+ * + * @param fn Function inside an Applicative + * @return Function to apply an Applicative's value to function + */ + public static ,T,T2,R> Function,AnyM2> ap(AnyM2,T2> fn){ + return apply->apply.adapter().ap(fn,apply); + } + /** + * Applicative ap2 method to use fluently to apply to a curried function + *
+     * {@code 
+     *    AnyM>> add = AnyM.fromNullable(Curry.curry2(this::add));
+     *    add.to(AnyM::ap2)
+     *       .apply(AnyM.ofNullable(10),AnyM.ofNullable(20));
+     *   
+     *    //AnyM[30] //add together
+     * 
+     * }
+     * 
+ * @param fn Curried function inside an Applicative + * @return Function to apply two Applicative's values to a function + */ + public static ,T,T2,R,T3> BiFunction,AnyM2,AnyM2> ap2(AnyM2>,T3> fn){ + return (apply1,apply2)->apply1.adapter().ap2(fn,apply1,apply2); + } + + /** + * Perform a filter operation on the wrapped monad instance e.g. + * + *
+     * {@code
+     *   AnyM.fromOptional(Optional.of(10)).filter(i->i<10);
+     * 
+     *   //AnyM[Optional.empty()]
+     *   
+     *   AnyM.fromStream(Stream.of(5,10)).filter(i->i<10);
+     *   
+     *   //AnyM[Stream[5]]
+     * }
+     * 
+     * 
+     * 
+ * + * @param fn Filtering predicate + * @return Filtered AnyM + */ + default AnyM2 filter(Predicate fn){ + return adapter().filter(this, fn); + } + + + default AnyM2 coflatMapA(final Function, R> mapper) { + return unit(Lambda.λ(()->mapper.apply(this))).map(Supplier::get); + } + + + default AnyM2,T2> nestA() { + return unit(this); + } + + /* (non-Javadoc) + * @see com.aol.cyclops2.types.EmptyUnit#emptyUnit() + */ + @Override + default Unit emptyUnit(){ + return adapter().empty(); + } + + /** + * Tests for equivalency between two AnyM types + * + *
+     * {@code
+     *    boolean eqv = AnyM.fromOptional(Optional.of(1)).eqv(AnyM.fromStream(Stream.of(1)));
+     *    //true
+     *     boolean eqv = AnyM.fromOptional(Optional.of(1)).eqv(AnyM.fromStream(Stream.of(1,2)));
+     *    //false
+     * }
+     * 
+ * + * @param t AnyM to check for equivalence with this AnyM + * @return true if monads are equivalent + */ + default boolean eqv(final AnyM2 t) { + return Predicates.eqvIterable(t) + .test(this); + } + + /** + * Allows structural matching on the value / seq nature of this AnyM. + * If this AnyM can only store a single value an Xor.secondary with type AnyMValue is returned + * If this AnyM can store one or many values an Xor.primary with type AnyMSeq is returned + * + *
+     * {@code
+     *    AnyM monad;
+     *    
+     *    monad.matchable().visit(v->handleValue(v.get()),s->handleSequence(s.toList()));
+     * }
+     * 
+ * + * + * @return An Xor for pattern matching either an AnyMValue or AnyMSeq + */ + Xor, AnyMSeq> matchable(); + + + + + /* + * Convert this AnyM to an extended Stream (ReactiveSeq) + * + *
+     * {@code 
+     *    AnyM monad =  AnyM.fromOptional(Optional.of(10));
+     *    
+     *    Stream reactiveStream = monad.reactiveStream();
+     *    //ReactiveSeq[10]
+     * }
+     * 
+ * + */ + @Override + default ReactiveSeq stream(){ + return ReactiveSeq.fromIterable(this); + } + + + + /** + * Perform a peek operation on the wrapped monad e.g. + * + *
+     * {@code 
+     *   AnyM.fromCompletableFuture(CompletableFuture.supplyAsync(()->loadData())
+     *       .peek(System.out::println)
+     * }
+     * 
+ * + * @param c Consumer to accept current data + * @return AnyM after peek operation + */ + @Override + default AnyM2 peek(Consumer c){ + return (AnyM2) AnyM.super.peek(c); + } + + + + /** + * join / flatten one level of a nested hierarchy + * + * @return Flattened / joined one level + */ + static ,T1,T2> AnyM2 flatten(AnyM2,T2> nested){ + return nested.flatMapA(Function.identity()); + } + static ,T1,T2> AnyM2 flattenI(AnyM2,T2> nested){ + return nested.flatMapI(Function.identity()); + } + + + /** + * Aggregate the contents of this Monad and the supplied Monad + * + *
{@code 
+     * 
+     * AnyM.fromStream(Stream.of(1,2,3,4))
+     * 							.aggregate(fromEither5(Optional.of(5)))
+     * 
+     * AnyM[Stream[List[1,2,3,4,5]]
+     * 
+     * List result = AnyM.fromStream(Stream.of(1,2,3,4))
+     * 							.aggregate(fromEither5(Optional.of(5)))
+     * 							.toSequence()
+     *                          .flatten()
+     * 							.toList();
+    	
+    	assertThat(result,equalTo(Arrays.asList(1,2,3,4,5)));
+    	}
+ * + * @param next Monad to aggregate content with + * @return Aggregated Monad + */ + default AnyM2,T2> aggregate(AnyM2 next){ + return unit(Stream.concat(matchable().visit(value -> value.stream(), seq -> seq.stream()), next.matchable() + .visit(value -> value.stream(), + seq -> seq.stream())) + .collect(Collectors.toList())); + } + + + + + /** + * Construct an AnyM wrapping a new empty instance of the wrapped type + * + * e.g. + *
+     * {@code 
+     * Any ints = AnyM.fromStream(Stream.of(1,2,3));
+     * AnyM empty=ints.empty();
+     * }
+     * 
+ * @return Empty AnyM + */ + default AnyM2 empty(){ + return adapter().empty(); + } + + + /** + * @return String representation of this AnyM + */ + @Override + public String toString(); + + + + /** + * Take an iterable containing Streamables and convert them into a List of AnyMs + * e.g. + * {@code + * List> anyMs = AnyM.listFromStreamable(Arrays.asList(Arrays.asList(1,2,3).iterator(),Arrays.asList(10,20,30)).iterator(); + * + * //List[AnyM[Stream[1,2,3],Stream[10,20,30]]] + * } + * + * @param fromEither5 Iterable containing Iterators + * @return List of AnyMs + + public static ListX> listFromIterator(final Iterable> fromEither5) { + return StreamSupport.reactiveStream(fromEither5.spliterator(), false) + .map(i -> AnyM.fromIterable(() -> i)) + .collect(ListX.listXCollector()); + }*/ + + /** + * Convert a Collection of Monads to a Monad with a List + * + *
+     * {@code
+        List> futures = createFutures();
+        AnyM> futureList = AnyMonads.sequence(AsAnyMList.anyMList(futures));
+    
+       //where AnyM wraps  CompletableFuture>
+      }
+ * + * + * @param seq Collection of monads to convert + * @return Monad with a List + */ + public static ,T1,T2> AnyM2,T2> sequence(final Collection> seq, W w) { + return sequence(seq.stream(),w).map(ListX::fromStreamS); + } + + /** + * Convert a Collection of Monads to a Monad with a List applying the supplied function in the process + * + *
+     * {@code 
+       List> futures = createFutures();
+       AnyM> futureList = AnyMonads.traverse(AsAnyMList.anyMList(futures), (Integer i) -> "hello" +i);
+        }
+        
+ * + * @param seq Collection of Monads + * @param fn Function to apply + * @return Monad with a list + */ + public static ,T, R,T2> AnyM2,T2> traverse(final Collection> seq, final Function fn, W w) { + return sequence(seq,w).map(l->l.map(fn)); + } + + + + + public static ,T,T2> AnyM2,T2> sequence(Stream> stream, W witness) { + FunctionalAdapter c = witness.adapter(); + AnyM2,T2> identity = c.unit(ReactiveSeq.empty()); + + BiFunction,T2>,AnyM2,AnyM2,T2>> combineToStream = (acc, next) -> c.ap2(c.unit(Lambda.l2((Stream a)->(T b)->ReactiveSeq.concat(a,ReactiveSeq.of(b)))),acc,next); + + BinaryOperator,T2>> combineStreams = (a, b)-> (AnyM2,T2>)a.zip(b,(z1, z2)->(Stream)ReactiveSeq.concat(z1,z2)); // a.apply(b, (s1,s2)->s1); + + return stream.reduce(identity,combineToStream,combineStreams); + } + public static ,T,R,T2> AnyM2,T2> traverse(Function fn, Stream> stream, W witness) { + return sequence(stream.map(h->h.map(fn)),witness); + } + FunctionalAdapter adapter(); + + public static ,T,T2> AnyM2 narrow(AnyM2 anyM){ + return (AnyM2)anyM; + } + + /** + * Lift a function so it accepts an AnyM and returns an AnyM (any monad) + * AnyM view simplifies type related challenges. + * + * @param fn + * @return + */ + public static ,U, R> AnyMFn1 liftF(final Function fn) { + return u -> u.map(input -> fn.apply(input)); + } + + /** + * Lift a function so it accepts a Monad and returns a Monad (simplex view of a wrapped Monad) + * AnyM view simplifies type related challenges. The actual native type is not specified here. + * + * e.g. + * + *
{@code
+   *  BiFunction,AnyM,AnyM> add = Monads.liftF2(this::add);
+   *   
+   *  Optional result = add.apply(getBase(),getIncrease());
+   *  
+   *   private Integer add(Integer a, Integer b){
+              return a+b;
+      }
+   * }
+ * The add method has no null handling, but we can lift the method to Monadic form, and use Optionals to automatically handle null / empty value cases. + * + * + * @param fn BiFunction to lift + * @return Lifted BiFunction + */ + public static ,U1, U2, R> AnyMFn2 liftF2( + final BiFunction fn) { + + return (u1, u2) -> u1.flatMapA(input1 -> u2.map(input2 -> fn.apply(input1, input2))); + } + + + /** + * Lift a TriFunction into Monadic form. A good use case it to take an existing method and lift it so it can accept and return monads + * + *
+   * {@code
+   * TriFunction,AnyM,AnyM,AnyM> fn = liftF3(this::myMethod);
+   *    
+   * }
+   * 
+ * + * Now we can execute the Method with Streams, Optional, Futures, Try's etc to transparently inject iteration, null handling, async execution and / or error handling + * + * @param fn Function to lift + * @return Lifted function + */ + public static ,U1, U2, U3, R,T2> Fn3, AnyM2, AnyM2, AnyM2> liftF3( + final Function3 fn) { + return (u1, u2, u3) -> u1.flatMapA(input1 -> u2.flatMapA(input2 -> u3.map(input3 -> fn.apply(input1, input2, input3)))); + } + + + /** + * Lift a QuadFunction into Monadic form. + * + * @param fn Quad funciton to lift + * @return Lifted Quad function + */ + public static ,U1, U2, U3, U4, R,T2> Fn4, AnyM2, AnyM2, AnyM2, AnyM2> liftF4( + final Function4 fn) { + + return (u1, u2, u3, u4) -> u1.flatMapA(input1 -> u2.flatMapA(input2 -> u3.flatMapA(input3 -> u4.map(input4 -> fn.apply(input1, input2, input3, input4))))); + } + + /** + * Lift a jOOλ Function5 (5 parameters) into Monadic form + * + * @param fn Function to lift + * @return Lifted Function + */ + public static ,U1, U2, U3, U4, U5, R, T2> Fn5, AnyM2, AnyM2, AnyM2, AnyM2, AnyM2> liftF5( + final Function5 fn) { + + return (u1, u2, u3, u4, + u5) -> u1.flatMapA(input1 -> u2.flatMapA(input2 -> u3.flatMapA(input3 -> u4.flatMapA(input4 -> u5.map(input5 -> fn.apply(input1, input2, input3, + input4, input5)))))); + } + + + + /** + * Lift a Curried Function {@code(2 levels a->b->fn.apply(a,b) )} into Monadic form + * + * @param fn Function to lift + * @return Lifted function + */ + public static ,U1, U2, R, T2> Function, Function, AnyM2>> liftF2(final Function> fn) { + return u1 -> u2 -> u1.flatMapA(input1 -> u2.map(input2 -> fn.apply(input1) + .apply(input2))); + + } + + /** + * Lift a Curried Function {@code(3 levels a->b->c->fn.apply(a,b,c) )} into Monadic form + * + * @param fn Function to lift + * @return Lifted function + */ + public static ,U1, U2, U3, R, T2> Function, Function, Function, AnyM2>>> liftF3( + final Function>> fn) { + return u1 -> u2 -> u3 -> u1.flatMapA(input1 -> u2.flatMapA(input2 -> u3.map(input3 -> fn.apply(input1) + .apply(input2) + .apply(input3)))); + } + + /** + * Lift a Curried Function {@code(4 levels a->b->c->d->fn.apply(a,b,c,d) )} into Monadic form + * + * @param fn Function to lift + * @return Lifted function + */ + public static ,U1, U2, U3, U4, R,T2> Function, Function, Function, Function, AnyM2>>>> liftF4( + final Function>>> fn) { + + return u1 -> u2 -> u3 -> u4 -> u1.flatMapA(input1 -> u2.flatMapA(input2 -> u3.flatMapA(input3 -> u4.map(input4 -> fn.apply(input1) + .apply(input2) + .apply(input3) + .apply(input4))))); + } + + /** + * Lift a Curried Function {@code (5 levels a->b->c->d->e->fn.apply(a,b,c,d,e) ) }into Monadic form + * + * @param fn Function to lift + * @return Lifted function + */ + public static ,U1, U2, U3, U4, U5, R, T2> Function, Function, Function, Function, Function, AnyM2>>>>> liftF5( + final Function>>>> fn) { + + return u1 -> u2 -> u3 -> u4 -> u5 -> u1.flatMapA(input1 -> u2.flatMapA(input2 -> u3.flatMapA(input3 -> u4.flatMapA(input4 -> u5.map(input5 -> fn.apply(input1) + .apply(input2) + .apply(input3) + .apply(input4) + .apply(input5)))))); + } + + default FutureT liftMFuture(Function> lift) { + + return FutureT.of(this.map(a -> lift.apply(a))); + } + + default ListT liftMList(Function> lift) { + return ListT.of(this.map(a -> lift.apply(a))); + } + + default FutureT liftMFuture() { + return FutureT.of(this.map(a -> Future.ofResult(a))); + } + + default ListT liftMListX() { + return ListT.of(this.map(a -> ListX.of(a))); + } + +} \ No newline at end of file diff --git a/src/main/java/cyclops/monads/Cokleisli.java b/src/main/java/cyclops/monads/Cokleisli.java new file mode 100644 index 0000000000..afa32e8276 --- /dev/null +++ b/src/main/java/cyclops/monads/Cokleisli.java @@ -0,0 +1,46 @@ +package cyclops.monads; + + +import com.aol.cyclops2.types.Transformable; +import cyclops.control.Xor; +import cyclops.function.Fn1; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import org.jooq.lambda.tuple.Tuple2; + +import java.util.function.Function; + +@AllArgsConstructor(access= AccessLevel.PRIVATE) +public class Cokleisli> implements Fn1,R>, + Transformable{ + + public final Fn1,R> fn; + + + @Override + public R apply(AnyM a) { + return fn.apply(a); + } + public Cokleisli map(Function mapper){ + return cokleisli(fn.andThen(mapper)); + } + + public Cokleisli,W> fanout(Cokleisli f2) { + return product(f2); + + } + + public Cokleisli,W> product(Cokleisli f2) { + return cokleisli(fn.product(f2)); + } + + + + public static > Cokleisli cokleisli(Function,? extends R> fn){ + return new Cokleisli(Fn1.narrow(fn)); + } + + + + +} diff --git a/src/main/java/cyclops/monads/Kleisli.java b/src/main/java/cyclops/monads/Kleisli.java index e4b6fcda69..f92f320b14 100644 --- a/src/main/java/cyclops/monads/Kleisli.java +++ b/src/main/java/cyclops/monads/Kleisli.java @@ -2,17 +2,21 @@ import com.aol.cyclops2.types.Transformable; -import cyclops.control.either.Either; +import cyclops.control.Xor; import cyclops.function.Fn1; +import lombok.AccessLevel; import lombok.AllArgsConstructor; +import org.jooq.lambda.tuple.Tuple; +import org.jooq.lambda.tuple.Tuple2; import java.util.function.Function; -@AllArgsConstructor +@AllArgsConstructor(access= AccessLevel.PRIVATE) public class Kleisli> implements Fn1>, Transformable{ public final Fn1> fn; + private final W type = null; @Override public AnyM apply(T a) { @@ -21,11 +25,11 @@ public AnyM apply(T a) { } public Kleisli map(Function mapper){ - return kliesli(fn.andThen(am->am.map(mapper))); + return kleisli(fn.andThen(am->am.map(mapper))); } public Kleisli flatMap(Function> mapper){ - return kliesli(fn.andThen(am->am.flatMapA(mapper))); + return kleisli(fn.andThen(am->am.flatMapA(mapper))); } public
Kleisli compose(Kleisli kleisli) { @@ -38,24 +42,38 @@ public Kleisli then(Kleisli kleisli) { } - public Kleisli, Either,W> merge(Kleisli merge, W type) { - Kleisli, W> first = then(lift(Either::left, type)); - Kleisli, W> second = merge.then(lift(Either::right, type)); + public <__> Kleisli, Xor,W> leftK() { + return kleisli(xr -> xr.visit(l -> fn.apply(l).map(Xor::secondary), r -> type.adapter().unit(r).map(Xor::primary))); + } + public <__> Kleisli, Xor<__,R>,W> rightK() { + return kleisli(xr -> xr.visit(l -> type.adapter().unit(l).map(Xor::secondary), r -> fn.apply(r).map(Xor::primary))); + } + public <__> Kleisli, Tuple2,W> firstK() { + return kleisli(xr -> xr.map((v1,v2) -> fn.apply(v1).map(r1-> Tuple.tuple(r1,v2)))); + } + public <__> Kleisli, Tuple2<__,R>,W> secondK() { + return kleisli(xr -> xr.map((v1,v2) -> fn.apply(v2).map(r2-> Tuple.tuple(v1,r2)))); + } + + + public Kleisli, Xor,W> merge(Kleisli merge, W type) { + Kleisli, W> first = then(lift(Xor::secondary, type)); + Kleisli, W> second = merge.then(lift(Xor::primary, type)); return first.fanIn(second); } - public Kleisli, R,W> fanIn(Kleisli fanIn) { + public Kleisli, R,W> fanIn(Kleisli fanIn) { return new Kleisli<>(e -> e.visit(this, fanIn)); } - private static > Kleisli kliesli(Function> fn){ + public static > Kleisli kleisli(Function> fn){ return new Kleisli(narrow(fn)); } - private static > Kleisli lift(Function fn, W type){ - return kliesli(fn.andThen(r->type.adapter().unit(r))); + public static > Kleisli lift(Function fn, W type){ + return kleisli(fn.andThen(r->type.adapter().unit(r))); } private static , R> Fn1> narrow(Function> fn) { From 741a3aaf5dc3340f24947a188251f57a108c74c9 Mon Sep 17 00:00:00 2001 From: John McClean Date: Sun, 5 Feb 2017 00:29:25 +0000 Subject: [PATCH 03/14] wip --- .../cyclops/control/ReaderWriterState.java | 42 ++++ src/main/java/cyclops/control/State.java | 203 ++++++++++++++++++ src/main/java/cyclops/control/Writer.java | 194 +++++++++++++++++ src/main/java/cyclops/function/Coreader.java | 33 +++ src/main/java/cyclops/function/Fn1.java | 8 +- src/main/java/cyclops/monads/AnyM2.java | 18 +- src/main/java/cyclops/monads/Kleisli.java | 26 +-- .../com/aol/cyclops2/control/Xor2Test.java | 4 +- src/test/java/cyclops/control/StateTest.java | 40 ++++ src/test/java/cyclops/free/FreeTest.java | 1 + 10 files changed, 541 insertions(+), 28 deletions(-) create mode 100644 src/main/java/cyclops/control/ReaderWriterState.java create mode 100644 src/main/java/cyclops/control/State.java create mode 100644 src/main/java/cyclops/control/Writer.java create mode 100644 src/main/java/cyclops/function/Coreader.java create mode 100644 src/test/java/cyclops/control/StateTest.java diff --git a/src/main/java/cyclops/control/ReaderWriterState.java b/src/main/java/cyclops/control/ReaderWriterState.java new file mode 100644 index 0000000000..dc8630a7b9 --- /dev/null +++ b/src/main/java/cyclops/control/ReaderWriterState.java @@ -0,0 +1,42 @@ +package cyclops.control; + +import cyclops.free.Free; +import cyclops.function.*; +import org.jooq.lambda.tuple.Tuple; +import org.jooq.lambda.tuple.Tuple2; + +import java.util.function.Function; + +/** + * Created by johnmcclean on 05/02/2017. + */ +public class ReaderWriterState { + + + Reader, T>>> runState; + + public Tuple2,T> run(S s) { + return Fn0.run(runState.apply(s)); + } + public T eval(S s) { + return Fn0.run(runState.apply(s)).v2; + } + public State map(Function mapper) { + return mapState(t -> Tuple.tuple(t.v1, mapper.apply(t.v2))); + } + public State mapState(Function, Tuple2> fn) { + return suspended(s -> runState.apply(s).map(t -> fn.apply(t.map((w,r)->w.getValue().map2(__->r))))); + } + private static State suspended(Fn1>> runF) { + return new State<>(s -> Fn0.suspend(Lambda.λK(()->runF.apply(s)))); + } + + public State flatMap(Function> f) { + return suspended(s -> runState.apply(s).flatMap(result -> Free.done(f.apply(result.v2).run(result.v1)))); + } + + public static ReaderWriterState rws(Function> runF, Monoid monoid) { + + return new State<>(s -> Free.done(runF.apply(s))); + } +} diff --git a/src/main/java/cyclops/control/State.java b/src/main/java/cyclops/control/State.java new file mode 100644 index 0000000000..e9008dae33 --- /dev/null +++ b/src/main/java/cyclops/control/State.java @@ -0,0 +1,203 @@ +package cyclops.control; + +import cyclops.control.Maybe.Nothing; +import cyclops.free.Free; +import cyclops.function.*; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import org.jooq.lambda.tuple.Tuple; +import org.jooq.lambda.tuple.Tuple2; + +import java.util.function.BiFunction; +import java.util.function.Function; + +@AllArgsConstructor(access = AccessLevel.PRIVATE) +public final class State { + + private final Fn1>> runState; + + + public Tuple2 run(S s) { + return Fn0.run(runState.apply(s)); + } + public T eval(S s) { + return Fn0.run(runState.apply(s)).v2; + } + public static State get() { + return state(s -> Tuple.tuple(s, s)); + } + + public static State transition(Function f) { + return state(s -> Tuple.tuple(f.apply(s),(Nothing)Maybe.none())); + } + + public static State transition(Function f, T value) { + return state(s -> Tuple.tuple(f.apply(s),value)); + } + + public State map(Function mapper) { + return mapState(t -> Tuple.tuple(t.v1, mapper.apply(t.v2))); + } + public State mapState(Function, Tuple2> fn) { + return suspended(s -> runState.apply(s).map(t -> fn.apply(t))); + } + private static State suspended(Fn1>> runF) { + return new State<>(s -> Fn0.suspend(Lambda.λK(()->runF.apply(s)))); + } + + public State flatMap(Function> f) { + return suspended(s -> runState.apply(s).flatMap(t -> Free.done(f.apply(t.v2).run(t.v1)))); + } + public static State constant(T constant) { + return state(s -> Tuple.tuple(s, constant)); + } + + /* + * Perform a For Comprehension over a State, accepting 3 generating function. + * This results in a four level nested internal iteration over the provided States. + * + *
+   * {@code
+   *
+   *   import static com.aol.cyclops2.reactor.States.forEach4;
+   *
+      forEach4(State.just(1),
+              a-> State.just(a+1),
+              (a,b) -> State.just(a+b),
+              a                  (a,b,c) -> State.just(a+b+c),
+              Tuple::tuple)
+   *
+   * }
+   * 
+ * + * @param value1 top level State + * @param value2 Nested State + * @param value3 Nested State + * @param value4 Nested State + * @param yieldingFunction Generates a result per combination + * @return State with a combined value generated by the yielding function + */ + public State forEach4(Function> value2, + BiFunction> value3, + Fn3> value4, + Fn4 yieldingFunction) { + + + return this.flatMap(in -> { + + State a = value2.apply(in); + return a.flatMap(ina -> { + State b = value3.apply(in,ina); + return b.flatMap(inb -> { + + State c = value4.apply(in,ina,inb); + + return c.map(in2 -> { + + return yieldingFunction.apply(in, ina, inb, in2); + + }); + + }); + + + }); + + + }); + + } + + + + /** + * Perform a For Comprehension over a State, accepting 2 generating function. + * This results in a three level nested internal iteration over the provided States. + * + *
+     * {@code
+     *
+     *   import static com.aol.cyclops2.reactor.States.forEach3;
+     *
+    forEach3(State.just(1),
+    a-> State.just(a+1),
+    (a,b) -> State.just(a+b),
+    Tuple::tuple)
+     *
+     * }
+     * 
+ * + * @param value1 top level State + * @param value2 Nested State + * @param value3 Nested State + * @param yieldingFunction Generates a result per combination + * @return State with a combined value generated by the yielding function + */ + public State forEach3(Function> value2, + BiFunction> value3, + Fn3 yieldingFunction) { + + return this.flatMap(in -> { + + State a = value2.apply(in); + return a.flatMap(ina -> { + State b = value3.apply(in,ina); + return b.map(in2 -> { + return yieldingFunction.apply(in, ina, in2); + + }); + + + + }); + + }); + + } + + + /** + * Perform a For Comprehension over a State, accepting a generating function. + * This results in a two level nested internal iteration over the provided States. + * + *
+     * {@code
+     *
+     *   import static com.aol.cyclops2.reactor.States.forEach;
+     *
+    forEach(State.just(1),
+    a-> State.just(a+1),
+    Tuple::tuple)
+     *
+     * }
+     * 
+ * + * @param value1 top level State + * @param value2 Nested State + * @param yieldingFunction Generates a result per combination + * @return State with a combined value generated by the yielding function + */ + public State forEach2(Function> value2, + BiFunction yieldingFunction) { + + return this.flatMap(in -> { + + State a = value2.apply(in); + return a.map(in2 -> { + return yieldingFunction.apply(in, in2); + + }); + + }); + + } + + public static State state(Function> runF) { + + return new State<>(s -> Free.done(runF.apply(s))); + } + + + + +} \ No newline at end of file diff --git a/src/main/java/cyclops/control/Writer.java b/src/main/java/cyclops/control/Writer.java new file mode 100644 index 0000000000..f626f1287e --- /dev/null +++ b/src/main/java/cyclops/control/Writer.java @@ -0,0 +1,194 @@ +package cyclops.control; + +import com.aol.cyclops2.types.MonadicValue; +import com.aol.cyclops2.types.Transformable; +import cyclops.function.Fn3; +import cyclops.function.Fn4; +import cyclops.function.Monoid; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.val; +import org.jooq.lambda.tuple.Tuple; +import org.jooq.lambda.tuple.Tuple2; + +import java.util.Arrays; +import java.util.Iterator; +import java.util.function.BiFunction; +import java.util.function.Function; + +@AllArgsConstructor(access= AccessLevel.PRIVATE) +@Getter +public final class Writer implements Transformable, Iterable { + + private final Tuple2 value; + private final Monoid monoid; + + public Writer map(Function mapper) { + return writer(mapper.apply(value.v1), value.v2, monoid); + } + + public Writer flatMap(Function> fn) { + Writer writer = fn.apply(value.v1); + return writer(writer.value.v1, writer.monoid.apply(value.v2, writer.value.v2), writer.monoid); + } + + public Writer write(W write){ + return writer(value.v1,monoid.apply(write,value.v2),monoid); + } + + /* + * Perform a For Comprehension over a Writer, accepting 3 generating function. + * This results in a four level nested internal iteration over the provided Writers. + * + *
+      * {@code
+      *
+      *   import static com.aol.cyclops2.reactor.Writers.forEach4;
+      *
+         forEach4(Writer.just(1),
+                 a-> Writer.just(a+1),
+                 (a,b) -> Writer.just(a+b),
+                 a                  (a,b,c) -> Writer.just(a+b+c),
+                 Tuple::tuple)
+      *
+      * }
+      * 
+ * + * @param value1 top level Writer + * @param value2 Nested Writer + * @param value3 Nested Writer + * @param value4 Nested Writer + * @param yieldingFunction Generates a result per combination + * @return Writer with a combined value generated by the yielding function + */ + public Writer forEach4(Function> value2, + BiFunction> value3, + Fn3> value4, + Fn4 yieldingFunction) { + + + return this.flatMap(in -> { + + Writer a = value2.apply(in); + return a.flatMap(ina -> { + Writer b = value3.apply(in,ina); + return b.flatMap(inb -> { + + Writer c = value4.apply(in,ina,inb); + + return c.map(in2 -> { + + return yieldingFunction.apply(in, ina, inb, in2); + + }); + + }); + + + }); + + + }); + + } + + + + /** + * Perform a For Comprehension over a Writer, accepting 2 generating function. + * This results in a three level nested internal iteration over the provided Writers. + * + *
+     * {@code
+     *
+     *   import static com.aol.cyclops2.reactor.Writers.forEach3;
+     *
+    forEach3(Writer.just(1),
+    a-> Writer.just(a+1),
+    (a,b) -> Writer.just(a+b),
+    Tuple::tuple)
+     *
+     * }
+     * 
+ * + * @param value1 top level Writer + * @param value2 Nested Writer + * @param value3 Nested Writer + * @param yieldingFunction Generates a result per combination + * @return Writer with a combined value generated by the yielding function + */ + public Writer forEach3(Function> value2, + BiFunction> value3, + Fn3 yieldingFunction) { + + return this.flatMap(in -> { + + Writer a = value2.apply(in); + return a.flatMap(ina -> { + Writer b = value3.apply(in,ina); + return b.map(in2 -> { + return yieldingFunction.apply(in, ina, in2); + + }); + + + + }); + + }); + + } + + + /** + * Perform a For Comprehension over a Writer, accepting a generating function. + * This results in a two level nested internal iteration over the provided Writers. + * + *
+     * {@code
+     *
+     *   import static com.aol.cyclops2.reactor.Writers.forEach;
+     *
+    forEach(Writer.just(1),
+    a-> Writer.just(a+1),
+    Tuple::tuple)
+     *
+     * }
+     * 
+ * + * @param value1 top level Writer + * @param value2 Nested Writer + * @param yieldingFunction Generates a result per combination + * @return Writer with a combined value generated by the yielding function + */ + public Writer forEach2(Function> value2, + BiFunction yieldingFunction) { + + return this.flatMap(in -> { + + Writer a = value2.apply(in); + return a.map(in2 -> { + return yieldingFunction.apply(in, in2); + + }); + + }); + + } + + public static Writer writer(T value, Monoid combiner) { + return new Writer(Tuple.tuple(value, combiner.zero()), combiner); + } + public static Writer writer(T value, W initial, Monoid combiner) { + return new Writer(Tuple.tuple(value, initial), combiner); + } + public static Writer writer(Tuple2 values, Monoid combiner) { + return new Writer(values, combiner); + } + + @Override + public Iterator iterator() { + return Arrays.asList(value.v1).iterator(); + } +} \ No newline at end of file diff --git a/src/main/java/cyclops/function/Coreader.java b/src/main/java/cyclops/function/Coreader.java new file mode 100644 index 0000000000..cf2357905b --- /dev/null +++ b/src/main/java/cyclops/function/Coreader.java @@ -0,0 +1,33 @@ +package cyclops.function; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Value; + +import java.util.function.Function; + +@Getter +@AllArgsConstructor(access = AccessLevel.PRIVATE) +public class Coreader { + + private final T extract; + private final R ask; + + + public Coreader map(Function fn) { + return new Coreader( fn.apply(extract),ask); + } + + public Coreader> nest() { + return new Coreader<>(this,ask); + } + + public Coreader coflatMap(Function,? extends B> fn) { + return nest().map(fn); + } + + public static Coreader coreader(T extract, R ask){ + return new Coreader<>(extract,ask); + } +} \ No newline at end of file diff --git a/src/main/java/cyclops/function/Fn1.java b/src/main/java/cyclops/function/Fn1.java index 326e027a01..7e5a547d54 100644 --- a/src/main/java/cyclops/function/Fn1.java +++ b/src/main/java/cyclops/function/Fn1.java @@ -76,11 +76,11 @@ default Fn1, Xor> merge(Function Fn1, R> fanIn(Function fanIn) { return e -> e.visit(this, fanIn); } - default <__> Fn1, Xor> left() { + default <__> Fn1, Xor> leftFn() { return either -> either.bimap(this,Function.identity()); } - default <__> Fn1, Xor<__,R>> right() { + default <__> Fn1, Xor<__,R>> rightFn() { return either -> either.bimap(Function.identity(),this); } @@ -90,11 +90,11 @@ default Fn1> product(Fn1 fn){ return in -> Tuple.tuple(apply(in),fn.apply(in)); } - default <__> Fn1, Tuple2> first() { + default <__> Fn1, Tuple2> firstFn() { return t-> Tuple.tuple(apply(t.v1),t.v2); } - default <__> Fn1, Tuple2<__, R>> second() { + default <__> Fn1, Tuple2<__, R>> secondFn() { return t-> Tuple.tuple(t.v1,apply(t.v2)); } diff --git a/src/main/java/cyclops/monads/AnyM2.java b/src/main/java/cyclops/monads/AnyM2.java index da3803f5f3..f8d3a7bf80 100644 --- a/src/main/java/cyclops/monads/AnyM2.java +++ b/src/main/java/cyclops/monads/AnyM2.java @@ -120,10 +120,10 @@ default AnyMSeq unitIterator(Iterator U){ AnyM2 flatMapP(Function> fn); AnyM2 flatMapS(Function> fn); default AnyM2 flatMapA(Function> fn){ - return adapter().flatMap(this, fn); + return (AnyM2)adapter().flatMap(this, fn); } default AnyM2 map(Function fn){ - return adapter().map(this, fn); + return (AnyM2)adapter().map(this, fn); } default AnyM2 fromIterable(Iterable t){ return (AnyM2)adapter().unitIterable(t); @@ -195,7 +195,7 @@ default AnyM2 zip4(final Iterable second, */ @Override default AnyM2 unit(T t){ - return adapter().unit(t); + return (AnyM2)adapter().unit(t); } /** @@ -216,7 +216,7 @@ default AnyM2 unit(T t){ * @return Function to apply an Applicative's value to function */ public static ,T,T2,R> Function,AnyM2> ap(AnyM2,T2> fn){ - return apply->apply.adapter().ap(fn,apply); + return apply->(AnyM2)apply.adapter().ap(fn,apply); } /** * Applicative ap2 method to use fluently to apply to a curried function @@ -234,7 +234,7 @@ public static ,T,T2,R> Function,AnyM2,T,T2,R,T3> BiFunction,AnyM2,AnyM2> ap2(AnyM2>,T3> fn){ - return (apply1,apply2)->apply1.adapter().ap2(fn,apply1,apply2); + return (apply1,apply2)->(AnyM2)apply1.adapter().ap2(fn,apply1,apply2); } /** @@ -258,7 +258,7 @@ public static ,T,T2,R,T3> BiFunction,AnyM * @return Filtered AnyM */ default AnyM2 filter(Predicate fn){ - return adapter().filter(this, fn); + return (AnyM2)adapter().filter(this, fn); } @@ -418,7 +418,7 @@ default AnyM2,T2> aggregate(AnyM2 next){ * @return Empty AnyM */ default AnyM2 empty(){ - return adapter().empty(); + return (AnyM2)adapter().empty(); } @@ -490,9 +490,9 @@ public static ,T, R,T2> AnyM2,T2> traverse(f public static ,T,T2> AnyM2,T2> sequence(Stream> stream, W witness) { FunctionalAdapter c = witness.adapter(); - AnyM2,T2> identity = c.unit(ReactiveSeq.empty()); + AnyM2,T2> identity = ( AnyM2)c.unit(ReactiveSeq.empty()); - BiFunction,T2>,AnyM2,AnyM2,T2>> combineToStream = (acc, next) -> c.ap2(c.unit(Lambda.l2((Stream a)->(T b)->ReactiveSeq.concat(a,ReactiveSeq.of(b)))),acc,next); + BiFunction,T2>,AnyM2,AnyM2,T2>> combineToStream = (acc, next) -> (AnyM2)c.ap2(c.unit(Lambda.l2((Stream a)->(T b)->ReactiveSeq.concat(a,ReactiveSeq.of(b)))),acc,next); BinaryOperator,T2>> combineStreams = (a, b)-> (AnyM2,T2>)a.zip(b,(z1, z2)->(Stream)ReactiveSeq.concat(z1,z2)); // a.apply(b, (s1,s2)->s1); diff --git a/src/main/java/cyclops/monads/Kleisli.java b/src/main/java/cyclops/monads/Kleisli.java index f92f320b14..113cbd8eb7 100644 --- a/src/main/java/cyclops/monads/Kleisli.java +++ b/src/main/java/cyclops/monads/Kleisli.java @@ -16,7 +16,7 @@ public class Kleisli> implements Fn1>, Transformable{ public final Fn1> fn; - private final W type = null; + private final W type; @Override public AnyM apply(T a) { @@ -25,34 +25,34 @@ public AnyM apply(T a) { } public Kleisli map(Function mapper){ - return kleisli(fn.andThen(am->am.map(mapper))); + return kleisli(fn.andThen(am->am.map(mapper)),type); } public Kleisli flatMap(Function> mapper){ - return kleisli(fn.andThen(am->am.flatMapA(mapper))); + return kleisli(fn.andThen(am->am.flatMapA(mapper)),type); } public
Kleisli compose(Kleisli kleisli) { - return new Kleisli(a -> kleisli.apply(a).flatMapA(this)); + return new Kleisli(a -> kleisli.apply(a).flatMapA(this),type); } public Kleisli then(Kleisli kleisli) { return new Kleisli(t->this.apply(t) - .flatMapA(kleisli)); + .flatMapA(kleisli),type); } public <__> Kleisli, Xor,W> leftK() { - return kleisli(xr -> xr.visit(l -> fn.apply(l).map(Xor::secondary), r -> type.adapter().unit(r).map(Xor::primary))); + return kleisli(xr -> xr.visit(l -> fn.apply(l).map(Xor::secondary), r -> type.adapter().unit(r).map(Xor::primary)),type); } public <__> Kleisli, Xor<__,R>,W> rightK() { - return kleisli(xr -> xr.visit(l -> type.adapter().unit(l).map(Xor::secondary), r -> fn.apply(r).map(Xor::primary))); + return kleisli(xr -> xr.visit(l -> type.adapter().unit(l).map(Xor::secondary), r -> fn.apply(r).map(Xor::primary)),type); } public <__> Kleisli, Tuple2,W> firstK() { - return kleisli(xr -> xr.map((v1,v2) -> fn.apply(v1).map(r1-> Tuple.tuple(r1,v2)))); + return kleisli(xr -> xr.map((v1,v2) -> fn.apply(v1).map(r1-> Tuple.tuple(r1,v2))),type); } public <__> Kleisli, Tuple2<__,R>,W> secondK() { - return kleisli(xr -> xr.map((v1,v2) -> fn.apply(v2).map(r2-> Tuple.tuple(v1,r2)))); + return kleisli(xr -> xr.map((v1,v2) -> fn.apply(v2).map(r2-> Tuple.tuple(v1,r2))),type); } @@ -64,16 +64,16 @@ public Kleisli, Xor,W> merge(Kleisli merge, W } public Kleisli, R,W> fanIn(Kleisli fanIn) { - return new Kleisli<>(e -> e.visit(this, fanIn)); + return new Kleisli<>(e -> e.visit(this, fanIn),type); } - public static > Kleisli kleisli(Function> fn){ - return new Kleisli(narrow(fn)); + public static > Kleisli kleisli(Function> fn, W type){ + return new Kleisli(narrow(fn),type); } public static > Kleisli lift(Function fn, W type){ - return kleisli(fn.andThen(r->type.adapter().unit(r))); + return kleisli(fn.andThen(r->type.adapter().unit(r)),type); } private static , R> Fn1> narrow(Function> fn) { diff --git a/src/test/java/com/aol/cyclops2/control/Xor2Test.java b/src/test/java/com/aol/cyclops2/control/Xor2Test.java index aa5405ff09..b6a07ff706 100644 --- a/src/test/java/com/aol/cyclops2/control/Xor2Test.java +++ b/src/test/java/com/aol/cyclops2/control/Xor2Test.java @@ -101,8 +101,8 @@ public void visit(){ } @Test public void visitXor(){ - assertThat(just.mapBoth(secondary->"no", primary->"yes"),equalTo(Xor.primary("yes"))); - assertThat(none.mapBoth(secondary->"no", primary->"yes"),equalTo(Xor.secondary("no"))); + assertThat(just.bimap(secondary->"no", primary->"yes"),equalTo(Xor.primary("yes"))); + assertThat(none.bimap(secondary->"no", primary->"yes"),equalTo(Xor.secondary("no"))); } @Test public void testToMaybe() { diff --git a/src/test/java/cyclops/control/StateTest.java b/src/test/java/cyclops/control/StateTest.java new file mode 100644 index 0000000000..e2013f3a82 --- /dev/null +++ b/src/test/java/cyclops/control/StateTest.java @@ -0,0 +1,40 @@ +package cyclops.control; + +import org.jooq.lambda.tuple.Tuple; +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.junit.Assert.*; + +/** + * Created by johnmcclean on 04/02/2017. + */ +public class StateTest { + + @Test + public void eval(){ + State state = State.state(s-> Tuple.tuple(s,10)); + assertThat(state.eval("hello"),equalTo(10)); + } + @Test + public void run(){ + State state = State.state(s-> Tuple.tuple(s,10)); + assertThat(state.run("hello"),equalTo(Tuple.tuple("hello",10))); + } + + @Test + public void map(){ + State state = State.state(s-> Tuple.tuple(s,10)) + .map(i->i*2); + assertThat(state.run("hello"),equalTo(Tuple.tuple("hello",20))); + } + @Test + public void flatMap(){ + State state = State.state(s-> Tuple.tuple(s,10)) + .flatMap(i->State.state(s->Tuple.tuple(s,i*2))); + assertThat(state.run("hello"),equalTo(Tuple.tuple("hello",20))); + } + + + +} \ No newline at end of file diff --git a/src/test/java/cyclops/free/FreeTest.java b/src/test/java/cyclops/free/FreeTest.java index fe0e7e4213..8b19d5cd2d 100644 --- a/src/test/java/cyclops/free/FreeTest.java +++ b/src/test/java/cyclops/free/FreeTest.java @@ -15,6 +15,7 @@ public final class FreeTest { private static Free fibonacci(long i){ return fibonacci(i,1,0); } + private static Free fibonacci(long n, long a, long b) { return n == 0 ? Free.done(b) : λK( ()->fibonacci(n-1, a+b, a)) .kindTo(Fn0::suspend) From dcea876015e4aec842baaecee7eabbad2e7fc3d6 Mon Sep 17 00:00:00 2001 From: John McClean Date: Sun, 5 Feb 2017 11:21:20 +0000 Subject: [PATCH 04/14] ReaderWriterState monad --- .../cyclops/control/ReaderWriterState.java | 47 +++++++++++-------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/src/main/java/cyclops/control/ReaderWriterState.java b/src/main/java/cyclops/control/ReaderWriterState.java index dc8630a7b9..2accd03ad5 100644 --- a/src/main/java/cyclops/control/ReaderWriterState.java +++ b/src/main/java/cyclops/control/ReaderWriterState.java @@ -2,41 +2,48 @@ import cyclops.free.Free; import cyclops.function.*; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; import org.jooq.lambda.tuple.Tuple; import org.jooq.lambda.tuple.Tuple2; +import org.jooq.lambda.tuple.Tuple3; +import java.util.function.BiFunction; import java.util.function.Function; -/** - * Created by johnmcclean on 05/02/2017. - */ -public class ReaderWriterState { +@AllArgsConstructor(access = AccessLevel.PRIVATE) +public class ReaderWriterState { - Reader, T>>> runState; + Monoid monoid; + BiFunction>> runState; - public Tuple2,T> run(S s) { - return Fn0.run(runState.apply(s)); + public Tuple3 run(R r,S s) { + return Fn0.run(runState.apply(r,s)); } - public T eval(S s) { - return Fn0.run(runState.apply(s)).v2; - } - public State map(Function mapper) { - return mapState(t -> Tuple.tuple(t.v1, mapper.apply(t.v2))); + + public ReaderWriterState map(Function mapper) { + + return mapState(t -> Tuple.tuple(t.v1, t.v2, mapper.apply(t.v3))); } - public State mapState(Function, Tuple2> fn) { - return suspended(s -> runState.apply(s).map(t -> fn.apply(t.map((w,r)->w.getValue().map2(__->r))))); + public ReaderWriterState mapState(Function, Tuple3> fn) { + return suspended((r,s) -> runState.apply(r,s).map(t3 -> fn.apply(t3)),monoid); } - private static State suspended(Fn1>> runF) { - return new State<>(s -> Fn0.suspend(Lambda.λK(()->runF.apply(s)))); + private static ReaderWriterState suspended(BiFunction>> runF, + Monoid monoid) { + + return new ReaderWriterState(monoid,(R r ,S s) -> Fn0.suspend(Lambda.λK(()->runF.apply(r,s)))); + } - public State flatMap(Function> f) { - return suspended(s -> runState.apply(s).flatMap(result -> Free.done(f.apply(result.v2).run(result.v1)))); + public ReaderWriterState flatMap(Function> f) { + + return suspended((r,s) -> runState.apply(r, s) + .flatMap(result -> Free.done(f.apply(result.v3).run(r, result.v2))),monoid); } - public static ReaderWriterState rws(Function> runF, Monoid monoid) { + public static ReaderWriterState rws(BiFunction> runF, Monoid monoid) { - return new State<>(s -> Free.done(runF.apply(s))); + return new ReaderWriterState(monoid,(r,s) -> Free.done(runF.apply(r,s))); } } From 60216adbfc1c8b32ae257a2e63cc16864613267f Mon Sep 17 00:00:00 2001 From: John McClean Date: Sun, 5 Feb 2017 11:49:33 +0000 Subject: [PATCH 05/14] initial ReaderT --- src/main/java/cyclops/monads/AnyM2.java | 10 + .../cyclops/monads/transformers/ReaderT.java | 186 ++++++++++++++++++ 2 files changed, 196 insertions(+) create mode 100644 src/main/java/cyclops/monads/transformers/ReaderT.java diff --git a/src/main/java/cyclops/monads/AnyM2.java b/src/main/java/cyclops/monads/AnyM2.java index f8d3a7bf80..18726b8fde 100644 --- a/src/main/java/cyclops/monads/AnyM2.java +++ b/src/main/java/cyclops/monads/AnyM2.java @@ -668,4 +668,14 @@ default ListT liftMListX() { return ListT.of(this.map(a -> ListX.of(a))); } + /** + * Fluent api for type conversion + * + * @param reduce Funtion to convert this type + * @return Converted type + */ + default R to2(Function,? extends R> reduce){ + return reduce.apply(this); + } + } \ No newline at end of file diff --git a/src/main/java/cyclops/monads/transformers/ReaderT.java b/src/main/java/cyclops/monads/transformers/ReaderT.java new file mode 100644 index 0000000000..f689537374 --- /dev/null +++ b/src/main/java/cyclops/monads/transformers/ReaderT.java @@ -0,0 +1,186 @@ +package cyclops.monads.transformers; + +import com.aol.cyclops2.types.*; +import com.aol.cyclops2.types.anyM.transformers.ValueTransformer; +import cyclops.async.Future; +import cyclops.control.Trampoline; +import cyclops.function.Fn3; +import cyclops.function.Fn4; +import cyclops.function.Reader; +import cyclops.monads.AnyM; +import cyclops.monads.AnyM2; +import cyclops.monads.WitnessType; +import cyclops.stream.ReactiveSeq; +import org.jooq.lambda.tuple.Tuple; +import org.jooq.lambda.tuple.Tuple2; +import org.jooq.lambda.tuple.Tuple3; +import org.jooq.lambda.tuple.Tuple4; +import org.reactivestreams.Publisher; + +import java.util.Iterator; +import java.util.concurrent.Executor; +import java.util.function.*; +import java.util.stream.Stream; + +/** +* Monad Transformer for Future's nested within another monadic type + + * + * FutureT allows the deeply wrapped Future to be manipulating within it's nested /contained context + * + * @author johnmcclean + * + * @param Type of data stored inside the nested Future(s) + */ +public final class ReaderT,T,R> implements To>, + Transformable{ + + private final AnyM2,T> run; + + + + + + /** + * @return The wrapped AnyM + */ + + public AnyM2,T> unwrap() { + return run; + } + + public R2 unwrapTo(Function,T>, ? extends R2> fn) { + return unwrap().to2(fn); + } + + private ReaderT(final AnyM2,T> run) { + this.run = run; + } + + + + + + /** + * Peek at the current value of the Future + *
+     * {@code 
+     *    FutureWT.of(AnyM.fromStream(Arrays.asFutureW(10))
+     *             .peek(System.out::println);
+     *             
+     *     //prints 10        
+     * }
+     * 
+ * + * @param peek Consumer to accept current value of Future + * @return FutureWT with peek call + */ + @Override + public ReaderT peek(final Consumer peek) { + return of(run.peek(reader -> reader.map(a -> { + peek.accept(a); + return a; + }))); + } + + /** + * Map the wrapped Future + * + *
+     * {@code 
+     *  FutureWT.of(AnyM.fromStream(Arrays.asFutureW(10))
+     *             .map(t->t=t+1);
+     *  
+     *  
+     *  //FutureWT>>
+     * }
+     * 
+ * + * @param f Mapping function for the wrapped Future + * @return FutureWT that applies the map function to the wrapped Future + */ + + public ReaderT map(final Function f) { + return new ReaderT( + run.map(o -> o.map(f))); + } + + + public ReaderT flatMap(final Function> f) { + + return new ReaderT( + run.map(o -> o.flatMap(f))); + + } + + public ReaderT flatMapT(final Function> f) { + return of(run.map(reader-> reader.flatMap(a -> f.apply(a).run.unwrap()))); + } + + + + + + + + + /** + * Construct an FutureWT from an AnyM that wraps a monad containing FutureWs + * + * @param monads AnyM that contains a monad wrapping an Future + * @return FutureWT + */ + public static ,T,R> ReaderT of(final AnyM2,T> monads) { + return new ReaderT<>( + monads); + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return String.format("ReaderT[%s]", run.unwrap().toString()); + } + + + + + + + + @Override + public int hashCode() { + return run.hashCode(); + } + + @Override + public boolean equals(final Object o) { + if (o instanceof ReaderT) { + return run.equals(((ReaderT) o).run); + } + return false; + } + + + public String mkString(){ + return toString(); + } + + @Override + public ReaderT cast(Class type) { + return (ReaderT)Transformable.super.cast(type); + } + + + + @Override + public ReaderT trampoline(Function> mapper) { + return (ReaderT)Transformable.super.trampoline(mapper); + } + + + +} \ No newline at end of file From 2d47c9e9bf8cb663bbab4a357cf9f8c149e08992 Mon Sep 17 00:00:00 2001 From: John McClean Date: Sun, 5 Feb 2017 11:52:22 +0000 Subject: [PATCH 06/14] use eager Xor rather than lazy Either? --- src/main/java/cyclops/function/Fn1.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/java/cyclops/function/Fn1.java b/src/main/java/cyclops/function/Fn1.java index 7e5a547d54..2aec3931a7 100644 --- a/src/main/java/cyclops/function/Fn1.java +++ b/src/main/java/cyclops/function/Fn1.java @@ -5,7 +5,6 @@ import java.util.function.Function; import cyclops.control.*; -import cyclops.control.either.Either; import cyclops.monads.Kleisli; import cyclops.monads.transformers.FutureT; import cyclops.monads.transformers.ListT; @@ -67,8 +66,8 @@ default Fn1 memoize(Cacheable c){ } default Fn1, Xor> merge(Function fn) { - Fn1> first = andThen(Either::left); - Function> second = fn.andThen(Either::right); + Fn1> first = andThen(Xor::secondary); + Function> second = fn.andThen(Xor::primary); return first.fanIn(second); } @@ -78,11 +77,11 @@ default Fn1, R> fanIn(Function fanIn) } default <__> Fn1, Xor> leftFn() { - return either -> either.bimap(this,Function.identity()); + return either-> either.bimap(this,Function.identity()); } default <__> Fn1, Xor<__,R>> rightFn() { - return either -> either.bimap(Function.identity(),this); + return either-> either.bimap(Function.identity(),this); } From 3ca8d711e11476683153dcc1adf06d60c5d3a597 Mon Sep 17 00:00:00 2001 From: John McClean Date: Mon, 6 Feb 2017 12:40:24 +0000 Subject: [PATCH 07/14] better Kleisli flatMap impl and for comprehensions --- src/main/java/cyclops/free/Free.java | 4 +- src/main/java/cyclops/function/Reader.java | 122 +++--------------- src/main/java/cyclops/monads/AnyM2.java | 1 - src/main/java/cyclops/monads/Kleisli.java | 121 ++++++++++++++--- .../cyclops/monads/transformers/ReaderT.java | 119 ++++++++++++++++- .../functions/fluent/reader/Application.java | 5 +- .../functions/fluent/reader/DITest.java | 8 ++ src/test/java/cyclops/monads/KleisliTest.java | 39 ++++++ 8 files changed, 281 insertions(+), 138 deletions(-) create mode 100644 src/test/java/cyclops/monads/KleisliTest.java diff --git a/src/main/java/cyclops/free/Free.java b/src/main/java/cyclops/free/Free.java index b8aeffbea2..f2eb57ab46 100644 --- a/src/main/java/cyclops/free/Free.java +++ b/src/main/java/cyclops/free/Free.java @@ -18,8 +18,8 @@ /** * Free monad for cyclops2 * - * Inspiration and influences by https://github.com/xuwei-k/free-monad-java/blob/master/src/main/java/free/Free.java - * and http://www.slideshare.net/kenbot/running-free-with-the-monads + * Inspiration and heavily influenced by https://github.com/xuwei-k/free-monad-java/blob/master/src/main/java/free/Free.java + * Other influences incl :- http://www.slideshare.net/kenbot/running-free-with-the-monads * and https://github.com/scalaz/scalaz/blob/series/7.2.x/core/src/main/scala/scalaz/Free.scala * and https://github.com/typelevel/cats/blob/master/free/src/main/scala/cats/free/Free.scala * diff --git a/src/main/java/cyclops/function/Reader.java b/src/main/java/cyclops/function/Reader.java index 3d7ab0fcca..b2a49e7a14 100644 --- a/src/main/java/cyclops/function/Reader.java +++ b/src/main/java/cyclops/function/Reader.java @@ -13,31 +13,7 @@ * * {@see
Dependency injection using the Reader Monad in Java 8} * - *
- * {@code 
- * For comprehension with the Reader Monad, using curried syntax :-
- *  
- * import com.aol.cyclops2.control.For;
- * 
- * Reader res =  For.reader(depth1("bob"))
-                                            .reader(a->depth2("bob"))
-                                            .reader(a->b->depth3("bob"))
-                                            .reader(a->b->c->depth3("bob"))
-                                            .reader(a->b->c->d->depth4("bob"))
-                                            .reader(a->b->c->d->e->depth5("bob"))
-                                            .reader(a->b->c->d->e->f->depth5("bob"))
-                                            .reader(a->b->c->d->e->f->g->depth6("bob"))
-                                            .yield(a->b->c->d->e->f->g->h->a+b+c+d+e+f+g+h).unwrap();
-   res.apply(new UserRepositoryImpl())
-   //29
-   private Reader depth8(String name){
-        return repo->depth7(name).apply(repo)+1;
-   }
- * 
- * 
- * }
- * 
- * + * * * @author johnmcclean * @@ -65,45 +41,21 @@ default Reader flatMap(final Function - * {@code - * - * import static com.aol.cyclops2.reactor.Readers.forEach4; - * - forEach4(Reader.just(1), - a-> Reader.just(a+1), - (a,b) -> Reader.just(a+b), - a (a,b,c) -> Reader.just(a+b+c), - Tuple::tuple) - * - * } - * - * - * @param value1 top level Reader - * @param value2 Nested Reader - * @param value3 Nested Reader - * @param value4 Nested Reader - * @param yieldingFunction Generates a result per combination - * @return Reader with a combined value generated by the yielding function - */ - default Reader forEach4(Function> value2, - BiFunction> value3, - Fn3> value4, + + default Reader forEach4(Function> value2, + BiFunction> value3, + Fn3> value4, Fn4 yieldingFunction) { return this.flatMap(in -> { - Reader a = value2.apply(in); + Reader a = FluentFunctions.of(value2.apply(in)); return a.flatMap(ina -> { - Reader b = value3.apply(in,ina); + Reader b = FluentFunctions.of(value3.apply(in,ina)); return b.flatMap(inb -> { - Reader c = value4.apply(in,ina,inb); + Reader c = FluentFunctions.of(value4.apply(in,ina,inb)); return c.map(in2 -> { @@ -123,38 +75,16 @@ default Reader forEach4(Function - * {@code - * - * import static com.aol.cyclops2.reactor.Readers.forEach3; - * - forEach3(Reader.just(1), - a-> Reader.just(a+1), - (a,b) -> Reader.just(a+b), - Tuple::tuple) - * - * } - * - * - * @param value1 top level Reader - * @param value2 Nested Reader - * @param value3 Nested Reader - * @param yieldingFunction Generates a result per combination - * @return Reader with a combined value generated by the yielding function - */ - default Reader forEach3(Function> value2, - BiFunction> value3, + + default Reader forEach3(Function> value2, + BiFunction> value3, Fn3 yieldingFunction) { return this.flatMap(in -> { - Reader a = value2.apply(in); + Reader a = FluentFunctions.of(value2.apply(in)); return a.flatMap(ina -> { - Reader b = value3.apply(in,ina); + Reader b = FluentFunctions.of(value3.apply(in,ina)); return b.map(in2 -> { return yieldingFunction.apply(in, ina, in2); @@ -169,33 +99,13 @@ default Reader forEach3(Function - * {@code - * - * import static com.aol.cyclops2.reactor.Readers.forEach; - * - forEach(Reader.just(1), - a-> Reader.just(a+1), - Tuple::tuple) - * - * } - * - * - * @param value1 top level Reader - * @param value2 Nested Reader - * @param yieldingFunction Generates a result per combination - * @return Reader with a combined value generated by the yielding function - */ - default Reader forEach2(Function> value2, + + default Reader forEach2(Function> value2, BiFunction yieldingFunction) { return this.flatMap(in -> { - Reader a = value2.apply(in); + Reader a = FluentFunctions.of(value2.apply(in)); return a.map(in2 -> { return yieldingFunction.apply(in, in2); diff --git a/src/main/java/cyclops/monads/AnyM2.java b/src/main/java/cyclops/monads/AnyM2.java index 18726b8fde..933ada758a 100644 --- a/src/main/java/cyclops/monads/AnyM2.java +++ b/src/main/java/cyclops/monads/AnyM2.java @@ -70,7 +70,6 @@ */ public interface AnyM2,T,T2> extends AnyM, Unwrapable, - // To>, EmptyUnit, Unit, Folds, diff --git a/src/main/java/cyclops/monads/Kleisli.java b/src/main/java/cyclops/monads/Kleisli.java index 113cbd8eb7..a1ccd0d8b9 100644 --- a/src/main/java/cyclops/monads/Kleisli.java +++ b/src/main/java/cyclops/monads/Kleisli.java @@ -3,16 +3,19 @@ import com.aol.cyclops2.types.Transformable; import cyclops.control.Xor; -import cyclops.function.Fn1; +import cyclops.function.*; +import cyclops.monads.transformers.ReaderT; import lombok.AccessLevel; import lombok.AllArgsConstructor; import org.jooq.lambda.tuple.Tuple; import org.jooq.lambda.tuple.Tuple2; +import java.util.function.BiFunction; import java.util.function.Function; +import java.util.stream.Stream; @AllArgsConstructor(access= AccessLevel.PRIVATE) -public class Kleisli> implements Fn1>, +public class Kleisli,T,R> implements Fn1>, Transformable{ public final Fn1> fn; @@ -24,55 +27,133 @@ public AnyM apply(T a) { return fn.apply(a); } - public Kleisli map(Function mapper){ + public Kleisli map(Function mapper){ return kleisli(fn.andThen(am->am.map(mapper)),type); } - - public Kleisli flatMap(Function> mapper){ + public Kleisli flatMapA(Function> mapper){ return kleisli(fn.andThen(am->am.flatMapA(mapper)),type); } + public Kleisli flatMap(Function> mapper){ + return kleisli(t->fn.apply(t).flatMapA(r -> mapper.apply(r).fn.apply(t)),type); + } - public Kleisli compose(Kleisli kleisli) { - return new Kleisli(a -> kleisli.apply(a).flatMapA(this),type); + public Kleisli compose(Kleisli kleisli) { + return new Kleisli(a -> kleisli.apply(a).flatMapA(this),type); } - public Kleisli then(Kleisli kleisli) { + public Kleisli then(Kleisli kleisli) { - return new Kleisli(t->this.apply(t) + return new Kleisli(t->this.apply(t) .flatMapA(kleisli),type); } - public <__> Kleisli, Xor,W> leftK() { + public <__> Kleisli, Xor> leftK() { return kleisli(xr -> xr.visit(l -> fn.apply(l).map(Xor::secondary), r -> type.adapter().unit(r).map(Xor::primary)),type); } - public <__> Kleisli, Xor<__,R>,W> rightK() { + public <__> Kleisli, Xor<__,R>> rightK() { return kleisli(xr -> xr.visit(l -> type.adapter().unit(l).map(Xor::secondary), r -> fn.apply(r).map(Xor::primary)),type); } - public <__> Kleisli, Tuple2,W> firstK() { + public <__> Kleisli, Tuple2> firstK() { return kleisli(xr -> xr.map((v1,v2) -> fn.apply(v1).map(r1-> Tuple.tuple(r1,v2))),type); } - public <__> Kleisli, Tuple2<__,R>,W> secondK() { + public <__> Kleisli, Tuple2<__,R>> secondK() { return kleisli(xr -> xr.map((v1,v2) -> fn.apply(v2).map(r2-> Tuple.tuple(v1,r2))),type); } - public Kleisli, Xor,W> merge(Kleisli merge, W type) { - Kleisli, W> first = then(lift(Xor::secondary, type)); - Kleisli, W> second = merge.then(lift(Xor::primary, type)); + public Kleisli, Xor> merge(Kleisli merge, W type) { + Kleisli> first = then(lift(Xor::secondary, type)); + Kleisli> second = merge.then(lift(Xor::primary, type)); return first.fanIn(second); } - public Kleisli, R,W> fanIn(Kleisli fanIn) { + public Kleisli, R> fanIn(Kleisli fanIn) { return new Kleisli<>(e -> e.visit(this, fanIn),type); } - public static > Kleisli kleisli(Function> fn, W type){ - return new Kleisli(narrow(fn),type); + public Kleisli forEach4(Function>> value2, + BiFunction>> value3, + Fn3>> value4, + Fn4 yieldingFunction) { + + + + Kleisli d2 = kleisli(t -> type.adapter().unit(yieldingFunction.apply(null, null, null, null)), type); + + return this.flatMap(in -> { + + Kleisli a = kleisli(value2.apply(in),type); + return a.flatMap(ina -> { + Kleisli b = kleisli(value3.apply(in,ina),type); + return b.flatMap(inb -> { + + Kleisli c = kleisli(value4.apply(in,ina,inb),type); + return c.map(inc->yieldingFunction.apply(in, ina, inb, inc)); + + }); + + + }); + + + }); + + } + + + + + public Kleisli forEach3(Function>> value2, + BiFunction>> value3, + Fn3 yieldingFunction) { + + return this.flatMap(in -> { + + Kleisli a = kleisli(value2.apply(in),type); + return a.flatMap(ina -> { + Kleisli b = kleisli(value3.apply(in,ina),type); + return b.map(in2 -> { + return yieldingFunction.apply(in, ina, in2); + + }); + + + + }); + + }); + + } + + + + public Kleisli forEach2(Function>> value2, + BiFunction yieldingFunction) { + + return this.flatMap(in -> { + + Kleisli a = kleisli(value2.apply(in),type); + return a.map(in2 -> { + return yieldingFunction.apply(in, in2); + + }); + + + + + }); + + + } + + + public static > Kleisli kleisli(Function> fn, W type){ + return new Kleisli(narrow(fn),type); } - public static > Kleisli lift(Function fn, W type){ + public static > Kleisli lift(Function fn, W type){ return kleisli(fn.andThen(r->type.adapter().unit(r)),type); } diff --git a/src/main/java/cyclops/monads/transformers/ReaderT.java b/src/main/java/cyclops/monads/transformers/ReaderT.java index f689537374..e8f19a07ae 100644 --- a/src/main/java/cyclops/monads/transformers/ReaderT.java +++ b/src/main/java/cyclops/monads/transformers/ReaderT.java @@ -4,9 +4,7 @@ import com.aol.cyclops2.types.anyM.transformers.ValueTransformer; import cyclops.async.Future; import cyclops.control.Trampoline; -import cyclops.function.Fn3; -import cyclops.function.Fn4; -import cyclops.function.Reader; +import cyclops.function.*; import cyclops.monads.AnyM; import cyclops.monads.AnyM2; import cyclops.monads.WitnessType; @@ -33,7 +31,7 @@ * @param Type of data stored inside the nested Future(s) */ public final class ReaderT,T,R> implements To>, - Transformable{ + Transformable, Fn1 { private final AnyM2,T> run; @@ -105,7 +103,6 @@ public ReaderT map(final Function f) { run.map(o -> o.map(f))); } - public ReaderT flatMap(final Function> f) { return new ReaderT( @@ -145,10 +142,115 @@ public String toString() { return String.format("ReaderT[%s]", run.unwrap().toString()); } - + + public ReaderT forEach4M(Function> value1, + BiFunction> value2, + Fn3> value3, + Fn4 yieldingFunction) { + return this.flatMapT(in->value1.apply(in) + .flatMapT(in2-> value2.apply(in,in2) + .flatMapT(in3->value3.apply(in,in2,in3) + .map(in4->yieldingFunction.apply(in,in2,in3,in4))))); + + } + + + public ReaderT forEach3M(Function> value1, + BiFunction> value2, + Fn3 yieldingFunction) { + + return this.flatMapT(in->value1.apply(in).flatMapT(in2-> value2.apply(in,in2) + .map(in3->yieldingFunction.apply(in,in2,in3)))); + + } + + + public ReaderT forEach2M(Function> value1, + BiFunction yieldingFunction) { + + + return this.flatMapT(in->value1.apply(in) + .map(in2->yieldingFunction.apply(in,in2))); + } + + + public ReaderT forEach4(Function> value2, + BiFunction> value3, + Fn3> value4, + Fn4 yieldingFunction) { + + + return this.flatMap(in -> { + + Reader a = FluentFunctions.of(value2.apply(in)); + return a.flatMap(ina -> { + Reader b = FluentFunctions.of(value3.apply(in,ina)); + return b.flatMap(inb -> { + + Reader c = FluentFunctions.of(value4.apply(in,ina,inb)); + + return c.map(in2 -> { + + return yieldingFunction.apply(in, ina, inb, in2); + + }); + + }); + + + }); + + + }); + + } + + + + + public ReaderT forEach3(Function> value2, + BiFunction> value3, + Fn3 yieldingFunction) { + + return this.flatMap(in -> { + + Reader a = FluentFunctions.of(value2.apply(in)); + return a.flatMap(ina -> { + Reader b = FluentFunctions.of(value3.apply(in,ina)); + return b.map(in2 -> { + return yieldingFunction.apply(in, ina, in2); + + }); + + + + }); + + }); + + } + public ReaderT forEach2(Function> value2, + BiFunction yieldingFunction) { + + return this.flatMap(in -> { + + Reader a = FluentFunctions.of(value2.apply(in)); + return a.map(in2 -> { + return yieldingFunction.apply(in, in2); + + }); + + + + + }); + + + } + @Override @@ -182,5 +284,8 @@ public ReaderT trampoline(Function userInfo(String username) { return run(new UserInfo().userInfo(username)); } diff --git a/src/test/java/com/aol/cyclops2/functions/fluent/reader/DITest.java b/src/test/java/com/aol/cyclops2/functions/fluent/reader/DITest.java index e0517ef96e..6b62ffd958 100644 --- a/src/test/java/com/aol/cyclops2/functions/fluent/reader/DITest.java +++ b/src/test/java/com/aol/cyclops2/functions/fluent/reader/DITest.java @@ -1,12 +1,17 @@ package com.aol.cyclops2.functions.fluent.reader; +import cyclops.async.Future; +import cyclops.control.Maybe; import cyclops.function.FluentFunctions; +import cyclops.function.Fn1; import cyclops.function.Reader; import com.aol.cyclops2.functions.fluent.reader.Application.UserRepositoryImpl; import org.junit.Test; +import java.util.Date; import java.util.HashMap; import java.util.Map; +import java.util.function.Function; import static org.hamcrest.Matchers.equalTo; import static org.junit.Assert.assertThat; @@ -21,6 +26,9 @@ public class DITest { put("email","bob@user.com"); put("boss","boss"); }}; + + + @Test public void test(){ assertThat(new Application().userInfo("bob"), equalTo(map)); diff --git a/src/test/java/cyclops/monads/KleisliTest.java b/src/test/java/cyclops/monads/KleisliTest.java new file mode 100644 index 0000000000..f5af7e77e5 --- /dev/null +++ b/src/test/java/cyclops/monads/KleisliTest.java @@ -0,0 +1,39 @@ +package cyclops.monads; + +import org.junit.Test; + +import java.util.stream.Stream; + +import static org.junit.Assert.*; + +/** + * Created by johnmcclean on 06/02/2017. + */ +public class KleisliTest { + + @Test + public void flatMap(){ + Kleisli k1 = Kleisli.kleisli(t -> AnyM.fromArray(1), Witness.stream.INSTANCE); + + k1.flatMap(i->Kleisli.kleisli(t->AnyM.fromArray(i+t),Witness.stream.INSTANCE)) + .apply(10) + .forEach(System.out::println); + } + @Test + public void flatMapA(){ + Kleisli k1 = Kleisli.kleisli(t -> AnyM.fromArray(1), Witness.stream.INSTANCE); + + k1.flatMapA(i->AnyM.fromArray(i+10)) + .apply(10) + .forEach(System.out::println); + } + @Test + public void forTest(){ + Kleisli k = Kleisli.kleisli(t -> AnyM.fromStream(Stream.of(t)), Witness.stream.INSTANCE); + + k.forEach4(r->Kleisli.kleisli(t->AnyM.fromStream(Stream.of(t)),Witness.stream.INSTANCE), + (Integer r,Integer r1)->t->AnyM.fromArray(r,r1,t), + (r,r1,r2)->t->AnyM.fromArray(r), + (r,r1,r2,r3)-> r+r1); + } +} \ No newline at end of file From 4c5b2e99b830a738462e897e770c0de74a131a7a Mon Sep 17 00:00:00 2001 From: John McClean Date: Mon, 6 Feb 2017 12:59:45 +0000 Subject: [PATCH 08/14] add write to rws --- src/main/java/cyclops/control/ReaderWriterState.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/cyclops/control/ReaderWriterState.java b/src/main/java/cyclops/control/ReaderWriterState.java index 2accd03ad5..d6caba7310 100644 --- a/src/main/java/cyclops/control/ReaderWriterState.java +++ b/src/main/java/cyclops/control/ReaderWriterState.java @@ -22,6 +22,11 @@ public Tuple3 run(R r,S s) { return Fn0.run(runState.apply(r,s)); } + public ReaderWriterState write(W value) { + BiFunction>> fn = (r,s)->runState.apply(r,s).map(t3->Tuple.tuple(monoid.apply(t3.v1,value),t3.v2,t3.v3)); + return suspended(fn,monoid); + } + public ReaderWriterState map(Function mapper) { return mapState(t -> Tuple.tuple(t.v1, t.v2, mapper.apply(t.v3))); @@ -42,6 +47,8 @@ public ReaderWriterState flatMap(Function Free.done(f.apply(result.v3).run(r, result.v2))),monoid); } + + public static ReaderWriterState rws(BiFunction> runF, Monoid monoid) { return new ReaderWriterState(monoid,(r,s) -> Free.done(runF.apply(r,s))); From 82f8eeb2ad2ac74f1f233ae8802c0b936c05b452 Mon Sep 17 00:00:00 2001 From: John McClean Date: Mon, 6 Feb 2017 15:19:57 +0000 Subject: [PATCH 09/14] wip --- .../java/cyclops/control/ReaderWriterState.java | 13 ++++++++++++- src/main/java/cyclops/monads/Kleisli.java | 12 ++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/main/java/cyclops/control/ReaderWriterState.java b/src/main/java/cyclops/control/ReaderWriterState.java index d6caba7310..6fd06177f7 100644 --- a/src/main/java/cyclops/control/ReaderWriterState.java +++ b/src/main/java/cyclops/control/ReaderWriterState.java @@ -23,10 +23,21 @@ public Tuple3 run(R r,S s) { } public ReaderWriterState write(W value) { - BiFunction>> fn = (r,s)->runState.apply(r,s).map(t3->Tuple.tuple(monoid.apply(t3.v1,value),t3.v2,t3.v3)); + BiFunction>> fn = + (r,s)->runState.apply(r,s).map(t3->Tuple.tuple(monoid.apply(t3.v1,value),t3.v2,t3.v3)); + return suspended(fn,monoid); } + public ReaderWriterState ask() { + return suspended((r,s) -> runState.apply(r,s).map(t3 -> Tuple.tuple(monoid.zero(),s,t3.v3)),monoid); + } + + + public ReaderWriterState local(Function fn) { + BiFunction>> runFn = (R r, S s) -> runState.apply(fn.apply(r), s); + return suspended(runFn,monoid); + } public ReaderWriterState map(Function mapper) { return mapState(t -> Tuple.tuple(t.v1, t.v2, mapper.apply(t.v3))); diff --git a/src/main/java/cyclops/monads/Kleisli.java b/src/main/java/cyclops/monads/Kleisli.java index a1ccd0d8b9..65c84c7a02 100644 --- a/src/main/java/cyclops/monads/Kleisli.java +++ b/src/main/java/cyclops/monads/Kleisli.java @@ -14,6 +14,15 @@ import java.util.function.Function; import java.util.stream.Stream; + +/** + * Compose functions that return monads + * + * @param Monad kind + * @param Function input type + * @param Function return type + * (inside monad e.g. Kleisli[stream,String,Integer] represents a function that takes a String and returns a Stream of Integers) + */ @AllArgsConstructor(access= AccessLevel.PRIVATE) public class Kleisli,T,R> implements Fn1>, Transformable{ @@ -27,6 +36,9 @@ public AnyM apply(T a) { return fn.apply(a); } + public Kleisli local(Function local){ + return kleisli(t->fn.apply(t).map(r->local.apply(r)),type); + } public Kleisli map(Function mapper){ return kleisli(fn.andThen(am->am.map(mapper)),type); } From c226e07956a37850e8af424b13b34b1e5193cd0d Mon Sep 17 00:00:00 2001 From: John McClean Date: Mon, 6 Feb 2017 16:48:17 +0000 Subject: [PATCH 10/14] make Kleisli a functional interface --- .../cyclops/control/ReaderWriterState.java | 10 +- src/main/java/cyclops/control/State.java | 8 ++ src/main/java/cyclops/control/Writer.java | 3 + src/main/java/cyclops/function/AnyMFn1.java | 3 +- src/main/java/cyclops/monads/Kleisli.java | 129 +++++++++++------- src/main/java/cyclops/monads/Witness.java | 11 +- src/test/java/cyclops/monads/KleisliTest.java | 24 +++- 7 files changed, 125 insertions(+), 63 deletions(-) diff --git a/src/main/java/cyclops/control/ReaderWriterState.java b/src/main/java/cyclops/control/ReaderWriterState.java index 6fd06177f7..ebb532368e 100644 --- a/src/main/java/cyclops/control/ReaderWriterState.java +++ b/src/main/java/cyclops/control/ReaderWriterState.java @@ -15,6 +15,9 @@ @AllArgsConstructor(access = AccessLevel.PRIVATE) public class ReaderWriterState { + public static class µ { + } + Monoid monoid; BiFunction>> runState; @@ -38,6 +41,7 @@ public ReaderWriterState local(Function fn) { BiFunction>> runFn = (R r, S s) -> runState.apply(fn.apply(r), s); return suspended(runFn,monoid); } + public ReaderWriterState map(Function mapper) { return mapState(t -> Tuple.tuple(t.v1, t.v2, mapper.apply(t.v3))); @@ -55,7 +59,11 @@ private static ReaderWriterState suspended(BiFunction ReaderWriterState flatMap(Function> f) { return suspended((r,s) -> runState.apply(r, s) - .flatMap(result -> Free.done(f.apply(result.v3).run(r, result.v2))),monoid); + .flatMap(result -> Free.done(f.apply(result.v3) + .run(r, result.v2) + .map((w2,s2,r2)->Tuple.tuple(monoid.apply(w2,result.v1),s2,r2) + + ))),monoid); } diff --git a/src/main/java/cyclops/control/State.java b/src/main/java/cyclops/control/State.java index e9008dae33..d45a83a1c2 100644 --- a/src/main/java/cyclops/control/State.java +++ b/src/main/java/cyclops/control/State.java @@ -13,6 +13,8 @@ @AllArgsConstructor(access = AccessLevel.PRIVATE) public final class State { + public static class µ { + } private final Fn1>> runState; @@ -34,6 +36,9 @@ public static State transition(Function f public static State transition(Function f, T value) { return state(s -> Tuple.tuple(f.apply(s),value)); } + public State combine(State combine, BiFunction combiner) { + return flatMap(a -> combine.map(b -> combiner.apply(a,b))); + } public State map(Function mapper) { return mapState(t -> Tuple.tuple(t.v1, mapper.apply(t.v2))); @@ -197,6 +202,9 @@ public static State state(Function return new State<>(s -> Free.done(runF.apply(s))); } + public static State of(S s) { + return state(__ -> Tuple.tuple(s, (Nothing)Maybe.none())); + } diff --git a/src/main/java/cyclops/control/Writer.java b/src/main/java/cyclops/control/Writer.java index f626f1287e..10c5382b8a 100644 --- a/src/main/java/cyclops/control/Writer.java +++ b/src/main/java/cyclops/control/Writer.java @@ -21,6 +21,9 @@ @Getter public final class Writer implements Transformable, Iterable { + public static class µ { + } + private final Tuple2 value; private final Monoid monoid; diff --git a/src/main/java/cyclops/function/AnyMFn1.java b/src/main/java/cyclops/function/AnyMFn1.java index 03c36e7326..d90fabe4bd 100644 --- a/src/main/java/cyclops/function/AnyMFn1.java +++ b/src/main/java/cyclops/function/AnyMFn1.java @@ -1,12 +1,13 @@ package cyclops.function; import cyclops.monads.AnyM; +import cyclops.monads.Kleisli; import cyclops.monads.WitnessType; /** * Created by johnmcclean on 18/12/2016. */ @FunctionalInterface -public interface AnyMFn1,T1,R> extends Fn1,AnyM> { +public interface AnyMFn1,T1,R> extends Kleisli,R> { } diff --git a/src/main/java/cyclops/monads/Kleisli.java b/src/main/java/cyclops/monads/Kleisli.java index 65c84c7a02..caf1f55f92 100644 --- a/src/main/java/cyclops/monads/Kleisli.java +++ b/src/main/java/cyclops/monads/Kleisli.java @@ -23,86 +23,116 @@ * @param Function return type * (inside monad e.g. Kleisli[stream,String,Integer] represents a function that takes a String and returns a Stream of Integers) */ -@AllArgsConstructor(access= AccessLevel.PRIVATE) -public class Kleisli,T,R> implements Fn1>, +@FunctionalInterface +public interface Kleisli,T,R> extends Fn1>, Transformable{ - public final Fn1> fn; - private final W type; - - @Override - public AnyM apply(T a) { - - return fn.apply(a); + static class µ { } - public Kleisli local(Function local){ - return kleisli(t->fn.apply(t).map(r->local.apply(r)),type); + default Kleisli local(Function local){ + return kleisli(t->apply(t).map(r->local.apply(r))); } - public Kleisli map(Function mapper){ - return kleisli(fn.andThen(am->am.map(mapper)),type); + default Kleisli map(Function mapper){ + return kleisli(andThen(am->am.map(mapper))); } - public Kleisli flatMapA(Function> mapper){ - return kleisli(fn.andThen(am->am.flatMapA(mapper)),type); + default Kleisli flatMapA(Function> mapper){ + return kleisli(andThen(am->am.flatMapA(mapper))); } - public Kleisli flatMap(Function> mapper){ - return kleisli(t->fn.apply(t).flatMapA(r -> mapper.apply(r).fn.apply(t)),type); + + /** + * + * Compose functions that return monads. + * + * Example :- + * + *
+     *  {@code
+     *  import cyclops.monads.Witness.reactiveSeq;
+        import static cyclops.monads.Kleisli.kleisli;
+
+
+        Kleisli k1 = kleisli(t -> ReactiveSeq.iterate(0,i->ii+1)
+                                                                            .anyM(), reactiveSeq.INSTANCE);
+
+        k1.flatMap(i-> kleisli(t-> ReactiveSeq.of(t+i)
+                                              .anyM(), reactiveSeq.INSTANCE))
+          .apply(10)
+          .forEach(System.out::println);
+
+        10
+        11
+        12
+        13
+        14
+        15
+        16
+        17
+        18
+        19
+     *
+     * }
+ * + * @param mapper + * @param + * @return + */ + default Kleisli flatMap(Function> mapper){ + return kleisli(t->apply(t).flatMapA(r -> mapper.apply(r).apply(t))); } - public
Kleisli compose(Kleisli kleisli) { - return new Kleisli(a -> kleisli.apply(a).flatMapA(this),type); + default Kleisli compose(Kleisli kleisli) { + return a -> kleisli.apply(a).flatMapA(this); } - public Kleisli then(Kleisli kleisli) { + default Kleisli then(Kleisli kleisli) { - return new Kleisli(t->this.apply(t) - .flatMapA(kleisli),type); + return t-> apply(t).flatMapA(kleisli); } - public <__> Kleisli, Xor> leftK() { - return kleisli(xr -> xr.visit(l -> fn.apply(l).map(Xor::secondary), r -> type.adapter().unit(r).map(Xor::primary)),type); + default <__> Kleisli, Xor> leftK(W type) { + return kleisli(xr -> xr.visit(l -> apply(l).map(Xor::secondary), r -> type.adapter().unit(r).map(Xor::primary))); } - public <__> Kleisli, Xor<__,R>> rightK() { - return kleisli(xr -> xr.visit(l -> type.adapter().unit(l).map(Xor::secondary), r -> fn.apply(r).map(Xor::primary)),type); + default <__> Kleisli, Xor<__,R>> rightK(W type) { + return kleisli(xr -> xr.visit(l -> type.adapter().unit(l).map(Xor::secondary), r -> apply(r).map(Xor::primary))); } - public <__> Kleisli, Tuple2> firstK() { - return kleisli(xr -> xr.map((v1,v2) -> fn.apply(v1).map(r1-> Tuple.tuple(r1,v2))),type); + default <__> Kleisli, Tuple2> firstK() { + return kleisli(xr -> xr.map((v1,v2) -> apply(v1).map(r1-> Tuple.tuple(r1,v2)))); } - public <__> Kleisli, Tuple2<__,R>> secondK() { - return kleisli(xr -> xr.map((v1,v2) -> fn.apply(v2).map(r2-> Tuple.tuple(v1,r2))),type); + default <__> Kleisli, Tuple2<__,R>> secondK() { + return kleisli(xr -> xr.map((v1,v2) -> apply(v2).map(r2-> Tuple.tuple(v1,r2)))); } - public Kleisli, Xor> merge(Kleisli merge, W type) { + default Kleisli, Xor> merge(Kleisli merge, W type) { Kleisli> first = then(lift(Xor::secondary, type)); Kleisli> second = merge.then(lift(Xor::primary, type)); return first.fanIn(second); } - public Kleisli, R> fanIn(Kleisli fanIn) { - return new Kleisli<>(e -> e.visit(this, fanIn),type); + default Kleisli, R> fanIn(Kleisli fanIn) { + return e -> e.visit(this, fanIn); } - public Kleisli forEach4(Function>> value2, + default Kleisli forEach4(Function>> value2, BiFunction>> value3, Fn3>> value4, Fn4 yieldingFunction) { - Kleisli d2 = kleisli(t -> type.adapter().unit(yieldingFunction.apply(null, null, null, null)), type); return this.flatMap(in -> { - Kleisli a = kleisli(value2.apply(in),type); + Kleisli a = kleisli(value2.apply(in)); return a.flatMap(ina -> { - Kleisli b = kleisli(value3.apply(in,ina),type); + Kleisli b = kleisli(value3.apply(in,ina)); return b.flatMap(inb -> { - Kleisli c = kleisli(value4.apply(in,ina,inb),type); + Kleisli c = kleisli(value4.apply(in,ina,inb)); return c.map(inc->yieldingFunction.apply(in, ina, inb, inc)); }); @@ -118,15 +148,15 @@ public Kleisli forEach4(Function Kleisli forEach3(Function>> value2, + default Kleisli forEach3(Function>> value2, BiFunction>> value3, Fn3 yieldingFunction) { return this.flatMap(in -> { - Kleisli a = kleisli(value2.apply(in),type); + Kleisli a = kleisli(value2.apply(in)); return a.flatMap(ina -> { - Kleisli b = kleisli(value3.apply(in,ina),type); + Kleisli b = kleisli(value3.apply(in,ina)); return b.map(in2 -> { return yieldingFunction.apply(in, ina, in2); @@ -140,14 +170,12 @@ public Kleisli forEach3(Function Kleisli forEach2(Function>> value2, + default Kleisli forEach2(Function>> value2, BiFunction yieldingFunction) { return this.flatMap(in -> { - Kleisli a = kleisli(value2.apply(in),type); + Kleisli a = kleisli(value2.apply(in)); return a.map(in2 -> { return yieldingFunction.apply(in, in2); @@ -162,14 +190,17 @@ public Kleisli forEach2(Function> Kleisli kleisli(Function> fn, W type){ - return new Kleisli(narrow(fn),type); + public static > Kleisli kleisli(Function> fn){ + return in-> { + Fn1> fn1 = narrow(fn); + return fn1.apply(in); + }; } public static > Kleisli lift(Function fn, W type){ - return kleisli(fn.andThen(r->type.adapter().unit(r)),type); + return kleisli(fn.andThen(r->type.adapter().unit(r))); } - private static , R> Fn1> narrow(Function> fn) { + static , R> Fn1> narrow(Function> fn) { if(fn instanceof Fn1){ return (Fn1)fn; } diff --git a/src/main/java/cyclops/monads/Witness.java b/src/main/java/cyclops/monads/Witness.java index 821a4de2a1..c8531478bb 100644 --- a/src/main/java/cyclops/monads/Witness.java +++ b/src/main/java/cyclops/monads/Witness.java @@ -8,6 +8,7 @@ import java.util.concurrent.CompletableFuture; import java.util.stream.Stream; +import com.aol.cyclops2.internal.comprehensions.comprehenders.*; import cyclops.control.Eval; import cyclops.async.Future; import cyclops.control.Ior; @@ -28,12 +29,6 @@ import cyclops.collections.QueueX; import cyclops.collections.SetX; import cyclops.collections.SortedSetX; -import com.aol.cyclops2.internal.comprehensions.comprehenders.CollectionXAdapter; -import com.aol.cyclops2.internal.comprehensions.comprehenders.FutureAdapter; -import com.aol.cyclops2.internal.comprehensions.comprehenders.MonadicValueAdapter; -import com.aol.cyclops2.internal.comprehensions.comprehenders.OptionalAdapter; -import com.aol.cyclops2.internal.comprehensions.comprehenders.StreamAdapter; -import com.aol.cyclops2.internal.comprehensions.comprehenders.StreamableAdapter; import com.aol.cyclops2.types.MonadicValue; import com.aol.cyclops2.types.extensability.FunctionalAdapter; @@ -121,6 +116,8 @@ public static Ior ior(AnyM anyM){ public static Try Try(AnyM anyM){ return anyM.unwrap(); } + + public static enum stream implements StreamWitness{ INSTANCE; @@ -348,4 +345,4 @@ public FunctionalAdapter adapter() { } } -} + } diff --git a/src/test/java/cyclops/monads/KleisliTest.java b/src/test/java/cyclops/monads/KleisliTest.java index f5af7e77e5..49a4045b60 100644 --- a/src/test/java/cyclops/monads/KleisliTest.java +++ b/src/test/java/cyclops/monads/KleisliTest.java @@ -1,9 +1,13 @@ package cyclops.monads; +import cyclops.monads.Witness.stream; +import cyclops.monads.Witness.reactiveSeq; +import cyclops.stream.ReactiveSeq; import org.junit.Test; import java.util.stream.Stream; +import static cyclops.monads.Kleisli.kleisli; import static org.junit.Assert.*; /** @@ -13,15 +17,25 @@ public class KleisliTest { @Test public void flatMap(){ - Kleisli k1 = Kleisli.kleisli(t -> AnyM.fromArray(1), Witness.stream.INSTANCE); + Kleisli k1 = t -> AnyM.fromArray(1); - k1.flatMap(i->Kleisli.kleisli(t->AnyM.fromArray(i+t),Witness.stream.INSTANCE)) + k1.flatMap(i-> t->AnyM.fromArray(i+t)) + .apply(10) + .forEach(System.out::println); + } + @Test + public void example(){ + Kleisli k1 = t -> ReactiveSeq.iterate(0,i->ii+1) + .anyM(); + + k1.flatMap(i-> t-> ReactiveSeq.of(t+i) + .anyM()) .apply(10) .forEach(System.out::println); } @Test public void flatMapA(){ - Kleisli k1 = Kleisli.kleisli(t -> AnyM.fromArray(1), Witness.stream.INSTANCE); + Kleisli k1 = t -> AnyM.fromArray(1); k1.flatMapA(i->AnyM.fromArray(i+10)) .apply(10) @@ -29,9 +43,9 @@ public void flatMapA(){ } @Test public void forTest(){ - Kleisli k = Kleisli.kleisli(t -> AnyM.fromStream(Stream.of(t)), Witness.stream.INSTANCE); + Kleisli k = t -> AnyM.fromStream(Stream.of(t)); - k.forEach4(r->Kleisli.kleisli(t->AnyM.fromStream(Stream.of(t)),Witness.stream.INSTANCE), + k.forEach4(r-> t->AnyM.fromStream(Stream.of(t)), (Integer r,Integer r1)->t->AnyM.fromArray(r,r1,t), (r,r1,r2)->t->AnyM.fromArray(r), (r,r1,r2,r3)-> r+r1); From 5e6d4cf11ea260be2b2d1ee7c83d75ded0d5e47b Mon Sep 17 00:00:00 2001 From: John McClean Date: Thu, 9 Feb 2017 21:31:45 +0000 Subject: [PATCH 11/14] add some tests --- src/jmh/java/scrabble/NonParallelStreams.java | 2 +- .../internal/stream/ReactiveStreamX.java | 2 +- .../spliterators/IteratableSpliterator.java | 4 +- .../spliterators/push/ZippingOperator.java | 2 +- .../java/com/aol/cyclops2/types/Folds.java | 4 +- .../types/futurestream/SimpleReactStream.java | 6 +- src/main/java/cyclops/Functions.java | 55 ++++++++++-- .../cyclops/control/ReaderWriterState.java | 2 +- src/main/java/cyclops/control/Writer.java | 6 +- src/main/java/cyclops/free/Free.java | 38 ++++++++- .../java/cyclops/function/Predicates.java | 57 +++++++++---- src/main/java/cyclops/function/Reader.java | 34 ++++---- src/main/java/cyclops/stream/ReactiveSeq.java | 4 +- .../cyclops2/streams/BaseSequentialTest.java | 10 +-- src/test/java/cyclops/free/CharToy.java | 6 +- src/test/java/cyclops/free/FreeTest.java | 83 +++++++++++++++++-- src/test/java/cyclops/monads/KleisliTest.java | 17 +++- 17 files changed, 263 insertions(+), 69 deletions(-) diff --git a/src/jmh/java/scrabble/NonParallelStreams.java b/src/jmh/java/scrabble/NonParallelStreams.java index ae34c1fb76..3d33e83cac 100644 --- a/src/jmh/java/scrabble/NonParallelStreams.java +++ b/src/jmh/java/scrabble/NonParallelStreams.java @@ -14,7 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * along with this program; if not, tell to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ diff --git a/src/main/java/com/aol/cyclops2/internal/stream/ReactiveStreamX.java b/src/main/java/com/aol/cyclops2/internal/stream/ReactiveStreamX.java index c864276360..5fb6ebd662 100644 --- a/src/main/java/com/aol/cyclops2/internal/stream/ReactiveStreamX.java +++ b/src/main/java/com/aol/cyclops2/internal/stream/ReactiveStreamX.java @@ -1012,7 +1012,7 @@ public Topic broadcast(){ if(wip.compareAndSet(false,true)){ try { - //use the first consuming thread to write this Stream onto the Queue + //use the first consuming thread to tell this Stream onto the Queue s.request(1000-queue.size()); }finally { wip.set(false); diff --git a/src/main/java/com/aol/cyclops2/internal/stream/spliterators/IteratableSpliterator.java b/src/main/java/com/aol/cyclops2/internal/stream/spliterators/IteratableSpliterator.java index b32cc93d9c..5ae5119b2d 100644 --- a/src/main/java/com/aol/cyclops2/internal/stream/spliterators/IteratableSpliterator.java +++ b/src/main/java/com/aol/cyclops2/internal/stream/spliterators/IteratableSpliterator.java @@ -11,7 +11,7 @@ * Created by johnmcclean on 22/12/2016. */ -public class IteratableSpliterator extends Spliterators.AbstractSpliterator implements CopyableSpliterator, Printable { +public class IteratableSpliterator extends Spliterators.AbstractSpliterator implements CopyableSpliterator{ private final Iterable source; @@ -40,7 +40,7 @@ public boolean tryAdvance(Consumer action) { if(active==null) active=source.iterator(); if (active.hasNext()) { - action.accept(print(active.next())); + action.accept(active.next()); return true; } diff --git a/src/main/java/com/aol/cyclops2/internal/stream/spliterators/push/ZippingOperator.java b/src/main/java/com/aol/cyclops2/internal/stream/spliterators/push/ZippingOperator.java index 30d95c4678..001e8feb81 100644 --- a/src/main/java/com/aol/cyclops2/internal/stream/spliterators/push/ZippingOperator.java +++ b/src/main/java/com/aol/cyclops2/internal/stream/spliterators/push/ZippingOperator.java @@ -24,7 +24,7 @@ * Created by johnmcclean on 12/01/2017. */ @AllArgsConstructor -public class ZippingOperator implements Operator, Printable { +public class ZippingOperator implements Operator{ Operator left; diff --git a/src/main/java/com/aol/cyclops2/types/Folds.java b/src/main/java/com/aol/cyclops2/types/Folds.java index 4a8adbb603..bb700bc424 100644 --- a/src/main/java/com/aol/cyclops2/types/Folds.java +++ b/src/main/java/com/aol/cyclops2/types/Folds.java @@ -329,7 +329,7 @@ default String join(final String sep, final String start, final String end) { /** * Write each element within this Folds in turn to the supplied PrintStream * - * @param str PrintStream to write to + * @param str PrintStream to tell to */ default void print(final PrintStream str) { stream().print(str); @@ -338,7 +338,7 @@ default void print(final PrintStream str) { /** * Write each element within this Folds in turn to the supplied PrintWriter * - * @param writer PrintWriter to write to + * @param writer PrintWriter to tell to */ default void print(final PrintWriter writer) { stream().print(writer); diff --git a/src/main/java/com/aol/cyclops2/types/futurestream/SimpleReactStream.java b/src/main/java/com/aol/cyclops2/types/futurestream/SimpleReactStream.java index f69aaab16a..922f5f499c 100644 --- a/src/main/java/com/aol/cyclops2/types/futurestream/SimpleReactStream.java +++ b/src/main/java/com/aol/cyclops2/types/futurestream/SimpleReactStream.java @@ -772,7 +772,7 @@ default Stream> streamCompletableFutures() { *
      * {@code
      * List result = 	SimpleReactStream.of(1,2,3)
-     * 											 .merge(FutureStream.of(100,200,300))
+     * 											 .product(FutureStream.of(100,200,300))
                                                   .map(it ->it+"!!")
                                                   .toList();
         assertThat(result,equalTo(Arrays.asList("1!!","2!!","3!!","100!!","200!!","300!!")));
@@ -780,12 +780,12 @@ default  Stream> streamCompletableFutures() {
      * }
      * 
* - * @param s Stream to merge + * @param s Stream to product * * @return Next stage in reactiveStream * * @see - * com.aol.simple.react.reactiveStream.traits.FutureStream#merge(com.aol.simple. + * com.aol.simple.react.reactiveStream.traits.FutureStream#product(com.aol.simple. * react.reactiveStream.traits.SimpleReactStream) */ diff --git a/src/main/java/cyclops/Functions.java b/src/main/java/cyclops/Functions.java index 69a74b38aa..7717cf0e72 100644 --- a/src/main/java/cyclops/Functions.java +++ b/src/main/java/cyclops/Functions.java @@ -4,17 +4,17 @@ import com.aol.cyclops2.types.Unit; import cyclops.collections.ListX; import cyclops.control.Maybe; -import cyclops.function.Fn1; -import cyclops.function.Monoid; +import cyclops.function.*; import cyclops.monads.AnyM; import cyclops.monads.Witness; import cyclops.monads.WitnessType; import cyclops.stream.ReactiveSeq; import cyclops.typeclasses.monad.Monad; -import java.util.Arrays; -import java.util.List; +import java.util.*; +import java.util.function.BiFunction; import java.util.function.Function; +import java.util.function.Predicate; /** * Collection of useful functions @@ -27,7 +27,7 @@ * {@link cyclops.function.PartialApplicator} * {@link cyclops.function.Memoize} * {@link cyclops.function.FluentFunctions} - * {@link Fn1}F + * {@link Fn1} * {@link Fn2} * {@link Fn3} * {@link Fn4} @@ -102,4 +102,49 @@ public static final Fn1,? extends T> reduce(Monoid m .reduce(monoid.zero(),monoid); } + static Fn1 map(Map map) { + return map::get; + } + static Fn1> maybeMap(Map map) { + return k->Maybe.ofNullable(map.get(k)); + } + static Fn1> optionalMap(Map map) { + return k-> Optional.ofNullable(map.get(k)); + } + + static Function forEach4(Function fn, + Function> value2, + BiFunction> value3, + Fn3> value4, + Fn4 yieldingFunction) { + + Reader< T,R> rd = Reader.narrow(FluentFunctions.of(fn)); + return rd.forEach4(value2, value3, value4, yieldingFunction); + + + + } + + static Function forEach3(Function fn, + Function> value2, + BiFunction> value3, + Fn3 yieldingFunction) { + + + Reader< T,R> rd = Reader.narrow(FluentFunctions.of(fn)); + return rd.forEach3(value2, value3, yieldingFunction); + } + + + + static Function forEach2(Function fn, + Function> value2, + BiFunction yieldingFunction) { + + Reader< T,R> rd = Reader.narrow(FluentFunctions.of(fn)); + return rd.forEach2(value2, yieldingFunction); + + + } + } diff --git a/src/main/java/cyclops/control/ReaderWriterState.java b/src/main/java/cyclops/control/ReaderWriterState.java index ebb532368e..de9302db64 100644 --- a/src/main/java/cyclops/control/ReaderWriterState.java +++ b/src/main/java/cyclops/control/ReaderWriterState.java @@ -25,7 +25,7 @@ public Tuple3 run(R r,S s) { return Fn0.run(runState.apply(r,s)); } - public ReaderWriterState write(W value) { + public ReaderWriterState tell(W value) { BiFunction>> fn = (r,s)->runState.apply(r,s).map(t3->Tuple.tuple(monoid.apply(t3.v1,value),t3.v2,t3.v3)); diff --git a/src/main/java/cyclops/control/Writer.java b/src/main/java/cyclops/control/Writer.java index 10c5382b8a..4b701508ca 100644 --- a/src/main/java/cyclops/control/Writer.java +++ b/src/main/java/cyclops/control/Writer.java @@ -36,10 +36,14 @@ public Writer flatMap(Function write(W write){ + public Writer tell(W write){ return writer(value.v1,monoid.apply(write,value.v2),monoid); } + public Writer set(R value){ + return writer(value,this.value.v2,monoid); + } + /* * Perform a For Comprehension over a Writer, accepting 3 generating function. * This results in a four level nested internal iteration over the provided Writers. diff --git a/src/main/java/cyclops/free/Free.java b/src/main/java/cyclops/free/Free.java index f2eb57ab46..79ea837320 100644 --- a/src/main/java/cyclops/free/Free.java +++ b/src/main/java/cyclops/free/Free.java @@ -10,7 +10,10 @@ import cyclops.function.Fn5; import cyclops.typeclasses.functor.Functor; import lombok.AccessLevel; +import lombok.AllArgsConstructor; import lombok.NoArgsConstructor; +import org.jooq.lambda.tuple.Tuple; +import org.jooq.lambda.tuple.Tuple2; import java.util.function.BiFunction; import java.util.function.Function; @@ -29,7 +32,7 @@ * @param Data type of Transformable */ @NoArgsConstructor(access=AccessLevel.PRIVATE) -public abstract class Free implements Printable { +public abstract class Free { public Free forEach6(Function> value2, BiFunction> value3, @@ -155,9 +158,12 @@ public final Free forEach2(Function> value2) { } public static Free liftF(final Higher value, final Functor functor){ + return new Suspend(functor.map(Free::done, value)); } + + public static Free done(final T t){ return new Pure<>(t); } @@ -190,6 +196,36 @@ public abstract R visit(Function, ? extends R> done, public final Xor resume(final Functor functor, Function>,R> decoder) { return resume(functor).secondaryMap(decoder); } + + + + /* + * Functor and HKT decoder for Free + */ + @AllArgsConstructor + static class FreeF{ + + Functor functor; + Function>,?> decoder1; + + private Function>,X> decoder(){ + return (Function)decoder1; + } + public final Tuple2,Xor> product(Free free1, Free free2 ){ + + return Tuple.tuple(free1.resume(functor,decoder()),free2.resume(functor,decoder())); + + } + + } + + + public static final Tuple2,Xor> product(final Functor functor, Free free1, Function>,X1> decoder1, + Free free2, Function>,X2> decoder2 ){ + + return Tuple.tuple(free1.resume(functor,decoder1),free2.resume(functor,decoder2)); + + } public final Xor>, T> resume(final Functor functor) { return resumeInternal( functor).visit(Xor::secondary,Xor::primary,t->null); diff --git a/src/main/java/cyclops/function/Predicates.java b/src/main/java/cyclops/function/Predicates.java index 2cde7f4ebb..0ac6b85d19 100644 --- a/src/main/java/cyclops/function/Predicates.java +++ b/src/main/java/cyclops/function/Predicates.java @@ -5,10 +5,7 @@ import cyclops.collections.ListX; import com.aol.cyclops2.types.Value; -import java.util.Arrays; -import java.util.Collection; -import java.util.Objects; -import java.util.Optional; +import java.util.*; import java.util.function.Predicate; import java.util.stream.Stream; @@ -189,6 +186,9 @@ public static Predicate some(final T value) { public static final Predicate any() { return __; }; + public static final Predicate none() { + return t->false; + }; /** * Match against any object that is an instance of supplied type @@ -252,6 +252,10 @@ public static Predicate eq(final V value) { return test -> Objects.equals(test, value); } + public static Predicate not(final Predicate p) { + return p.negate(); + } + /** * Test for equivalence @@ -303,12 +307,28 @@ public static Predicate eqv2(final Value value) { } - public static Predicate not(final Predicate p) { - return p.negate(); + + public static Predicate and(Predicate... preds) + { + Predicate current= (Predicate)preds[0]; + for(int i=1;i)preds[i]); + } + return current; } + public static Predicate or(Predicate... preds) + { + Predicate current = (Predicate)preds[0]; + for(int i=1;i)preds[i]); + } + return current; + } + @SafeVarargs public static Predicate in(final T1... values){ + return test -> Arrays.asList(values) .contains(test); } @@ -380,23 +400,25 @@ public static Predicate instanceOf(final Class clazz) { @SafeVarargs public static Predicate allOf(final Predicate... preds) { - return test -> ReactiveSeq.of(preds) - .map(t -> t.test(test)) - .allMatch(r -> r); + Predicate current= (Predicate)preds[0]; + for(int i=1;i)preds[i]); + } + return current; } @SafeVarargs public static Predicate anyOf(final Predicate... preds) { - return test -> ReactiveSeq.of(preds) - .map(t -> t.test(test)) - .anyMatch(r -> r); + Predicate current = (Predicate)preds[0]; + for(int i=1;i)preds[i]); + } + return current; } @SafeVarargs public static Predicate noneOf(final Predicate... preds) { - return test -> ReactiveSeq.of(preds) - .map(t -> t.test(test)) - .noneMatch(r -> r); + return allOf(preds).negate(); } @SafeVarargs @@ -406,4 +428,9 @@ public static Predicate xOf(final int x, final Predicate r); } + + static Predicate inSet(Set set) { + return set::contains; + } + } diff --git a/src/main/java/cyclops/function/Reader.java b/src/main/java/cyclops/function/Reader.java index b2a49e7a14..c440700b31 100644 --- a/src/main/java/cyclops/function/Reader.java +++ b/src/main/java/cyclops/function/Reader.java @@ -42,25 +42,26 @@ default Reader flatMap(final Function Reader forEach4(Function> value2, - BiFunction> value3, - Fn3> value4, - Fn4 yieldingFunction) { + default Reader forEach4(Function> value2, + BiFunction> value3, + Fn3> value4, + Fn4 yieldingFunction) { - return this.flatMap(in -> { + Reader res = this.flatMap(in -> { - Reader a = FluentFunctions.of(value2.apply(in)); + Reader a = narrow(FluentFunctions.of(value2.apply(in))); return a.flatMap(ina -> { - Reader b = FluentFunctions.of(value3.apply(in,ina)); + Reader b = narrow(FluentFunctions.of(value3.apply(in,ina))); return b.flatMap(inb -> { - Reader c = FluentFunctions.of(value4.apply(in,ina,inb)); + Reader c = narrow(FluentFunctions.of(value4.apply(in,ina,inb))); return c.map(in2 -> { return yieldingFunction.apply(in, ina, inb, in2); + }); }); @@ -70,21 +71,24 @@ default Reader forEach4(Function)res; } + static Reader narrow(Reader broad){ + return (Reader)broad; + } - - default Reader forEach3(Function> value2, - BiFunction> value3, + default Reader forEach3(Function> value2, + BiFunction> value3, Fn3 yieldingFunction) { return this.flatMap(in -> { - Reader a = FluentFunctions.of(value2.apply(in)); + Reader a = narrow(FluentFunctions.of(value2.apply(in))); return a.flatMap(ina -> { - Reader b = FluentFunctions.of(value3.apply(in,ina)); + Reader b = narrow(FluentFunctions.of(value3.apply(in,ina))); return b.map(in2 -> { return yieldingFunction.apply(in, ina, in2); @@ -100,12 +104,12 @@ default Reader forEach3(Function Reader forEach2(Function> value2, + default Reader forEach2(Function> value2, BiFunction yieldingFunction) { return this.flatMap(in -> { - Reader a = FluentFunctions.of(value2.apply(in)); + Reader a = narrow(FluentFunctions.of(value2.apply(in))); return a.map(in2 -> { return yieldingFunction.apply(in, in2); diff --git a/src/main/java/cyclops/stream/ReactiveSeq.java b/src/main/java/cyclops/stream/ReactiveSeq.java index 81377a70b2..34305bfb7a 100644 --- a/src/main/java/cyclops/stream/ReactiveSeq.java +++ b/src/main/java/cyclops/stream/ReactiveSeq.java @@ -798,7 +798,7 @@ default R foldParallel(Function,? extends R> fn){ if(ref.get()==null && ref.compareAndSet(null,Continuation.empty())){ try { - //use the first consuming thread to write this Stream onto the Queue + //use the first consuming thread to tell this Stream onto the Queue this.spliterator().forEachRemaining(queue::offer); }finally { queue.close(); @@ -4838,7 +4838,7 @@ default Topic broadcast(){ if(wip.compareAndSet(false,true)){ try { - //use the first consuming thread to write this Stream onto the Queue + //use the first consuming thread to tell this Stream onto the Queue if(!split.tryAdvance(topic::offer)){ topic.close(); return Continuation.empty(); diff --git a/src/test/java/com/aol/cyclops2/streams/BaseSequentialTest.java b/src/test/java/com/aol/cyclops2/streams/BaseSequentialTest.java index e6a8273891..d409d0c27a 100644 --- a/src/test/java/com/aol/cyclops2/streams/BaseSequentialTest.java +++ b/src/test/java/com/aol/cyclops2/streams/BaseSequentialTest.java @@ -242,7 +242,7 @@ public void changes() { @Test public void publishToAndMerge() { for (int k = 0; k < ITERATIONS; k++) { - System.out.println("Publish to and merge iteration " + k); + System.out.println("Publish to and product iteration " + k); cyclops.async.Queue queue = QueueFactories.boundedNonBlockingQueue(10) .build(); @@ -406,10 +406,10 @@ public void mergePTest() { public void triplicateFanOut() { for (int k = 0; k < ITERATIONS; k++) { - System.out.println("******************Triplicate & merge.. " + k); - System.out.println("******************Triplicate & merge.. " + k); - System.out.println("******************Triplicate & merge.. " + k); - System.out.println("******************Triplicate & merge.. " + k); + System.out.println("******************Triplicate & product.. " + k); + System.out.println("******************Triplicate & product.. " + k); + System.out.println("******************Triplicate & product.. " + k); + System.out.println("******************Triplicate & product.. " + k); ListX res = of(1, 2, 3, 4, 5, 6, 7, 8, 9) .fanOut(s1 -> s1.peek(System.out::println).filter(i -> i % 3 == 0).map(i -> i * 2), s2 -> s2.filter(i -> i % 3 == 1).map(i -> i * 100), diff --git a/src/test/java/cyclops/free/CharToy.java b/src/test/java/cyclops/free/CharToy.java index f0b8736e16..650b14b78b 100644 --- a/src/test/java/cyclops/free/CharToy.java +++ b/src/test/java/cyclops/free/CharToy.java @@ -60,7 +60,7 @@ public Either3, CharBell
, CharDone> match() { } - public Z fold(final Fn2 output) { + public Z visit(final Fn2 output) { return output.apply(a, next); } @@ -82,7 +82,7 @@ public Either3, CharBell, CharDone> match() { } - public Z fold(final Fn1 bell) { + public Z visit(final Fn1 bell) { return bell.apply(next); } @@ -99,7 +99,7 @@ public Either3, CharBell, CharDone> match() { } - public Z fold(final Z done) { + public Z visit(final Z done) { return done; } diff --git a/src/test/java/cyclops/free/FreeTest.java b/src/test/java/cyclops/free/FreeTest.java index 8b19d5cd2d..8ece3ca3a2 100644 --- a/src/test/java/cyclops/free/FreeTest.java +++ b/src/test/java/cyclops/free/FreeTest.java @@ -1,9 +1,14 @@ package cyclops.free; +import static cyclops.free.CharToy.bell; +import static cyclops.free.CharToy.done; +import static cyclops.free.CharToy.output; import static cyclops.function.Fn0.SupplierKind; +import cyclops.control.Xor; import cyclops.function.Fn0; +import org.jooq.lambda.tuple.Tuple2; import org.junit.Test; import cyclops.free.CharToy.*; @@ -52,16 +57,68 @@ public void interpreter(){ assertThat(expected,equalTo( - showProgram(CharToy.output('A') - .forEach4(unit1 -> CharToy.bell(), - (unit1,unit2) -> CharToy.output('B'), - (u1,u2,u3)->CharToy.done())))); + showProgram(output('A') + .forEach4(unit1 -> bell(), + (unit1,unit2) -> output('B'), + (u1,u2,u3)-> done())))); } + @Test + public void interpreterInterleave(){ + String expected = "emitted A\n" + + "bell \n" + + "emitted B\n" + + "done\n"; + + + + Free<µ, Void> one = output('A') + .forEach4(__ -> bell(), + (__, ___) -> output('B'), + (__, ___, ____) -> done()); + + Free<µ, Void> two = output('C') + .forEach4(__ -> bell(), + (__, ___) -> output('D'), + (__, ___, ____) -> done()); + + + assertThat(expected,equalTo( + interleaveProgram(one,two))); + } + + static String interleaveProgram(Free program1,Free program2){ + + Tuple2>, R>, Xor>, R>> tuple = Free.product(CharToy.functor, program1, CharToy::narrowK, program2, CharToy::narrowK); + Xor>, R> a = tuple.v1; + Xor>, R> b = tuple.v2; + + + String one =a.visit( + r -> r.match() + .visit(o->interleaveOutput(o,program2), + FreeTest::handleBell, + FreeTest::handleDone) + , + FreeTest::handleReturn + ); + String two = b.visit( + r -> r.match() + .visit(o->interleaveOutput1(o,program1), + FreeTest::handleBell, + FreeTest::handleDone) + , + FreeTest::handleReturn + ); + return one +two; + + } + static String showProgram(Free program){ + Xor>, R> xor = program.resume(CharToy.functor, CharToy::narrowK); - return program.resume(CharToy.functor, CharToy::narrowK) + return program.resume(CharToy.functor, CharToy::narrowK) .visit( r -> r.match() .visit(FreeTest::handleOutput, @@ -76,14 +133,26 @@ static String handleReturn(R r){ return "return " + r + "\n"; } static String handleOutput(CharOutput> output){ - return output.fold((a, next) -> "emitted " + a + "\n" + showProgram(next)); + return output.visit((a, next) -> "emitted " + a + "\n" + showProgram(next)); } static String handleBell(CharBell> bell){ - return bell.fold(next -> "bell " + "\n" + showProgram(next)); + return bell.visit(next -> "bell " + "\n" + showProgram(next)); } static String handleDone(CharDone done){ return "done\n"; } + + static String interleaveOutput(CharOutput> output,Free program2){ + System.out.println("Running interA"); + return output.visit((a, next) -> "emitted " + a + "\n" + interleaveProgram(next,program2)); + } + + static String interleaveOutput1(CharOutput> output,Free program1){ + System.out.println("Running interB"); + return output.visit((a, next) -> "emitted " + a + "\n" + interleaveProgram(program1,next)); + } + + } \ No newline at end of file diff --git a/src/test/java/cyclops/monads/KleisliTest.java b/src/test/java/cyclops/monads/KleisliTest.java index 49a4045b60..af2d2e694e 100644 --- a/src/test/java/cyclops/monads/KleisliTest.java +++ b/src/test/java/cyclops/monads/KleisliTest.java @@ -1,13 +1,16 @@ package cyclops.monads; +import cyclops.collections.ListX; import cyclops.monads.Witness.stream; import cyclops.monads.Witness.reactiveSeq; import cyclops.stream.ReactiveSeq; import org.junit.Test; +import java.util.stream.Collectors; import java.util.stream.Stream; import static cyclops.monads.Kleisli.kleisli; +import static org.hamcrest.CoreMatchers.equalTo; import static org.junit.Assert.*; /** @@ -15,23 +18,29 @@ */ public class KleisliTest { + @Test + public void local(){ + Kleisli k1 = t -> AnyM.fromArray(t); + assertThat(ListX.of(3),equalTo(k1.local(i->i+1).apply(2).to(Witness::stream).collect(Collectors.toList()))); + } + @Test public void flatMap(){ Kleisli k1 = t -> AnyM.fromArray(1); - k1.flatMap(i-> t->AnyM.fromArray(i+t)) + assertThat(ListX.of(11),equalTo(k1.flatMap(i-> t->AnyM.fromArray(i+t)) .apply(10) - .forEach(System.out::println); + .collect(Collectors.toList()))); } @Test public void example(){ Kleisli k1 = t -> ReactiveSeq.iterate(0,i->ii+1) .anyM(); - k1.flatMap(i-> t-> ReactiveSeq.of(t+i) + assertThat(ListX.iterate(10,10,i->i+1),equalTo(k1.flatMap(i-> t-> ReactiveSeq.of(t+i) .anyM()) .apply(10) - .forEach(System.out::println); + .collect(Collectors.toList()))); } @Test public void flatMapA(){ From 6ed13e7434e90396e612900b5da167baa9da6f81 Mon Sep 17 00:00:00 2001 From: John McClean Date: Fri, 10 Feb 2017 11:23:49 +0000 Subject: [PATCH 12/14] add for comps --- .../cyclops/control/ReaderWriterState.java | 4 +- src/main/java/cyclops/free/FreePrograms.java | 230 ++++++++++++++++++ 2 files changed, 232 insertions(+), 2 deletions(-) create mode 100644 src/main/java/cyclops/free/FreePrograms.java diff --git a/src/main/java/cyclops/control/ReaderWriterState.java b/src/main/java/cyclops/control/ReaderWriterState.java index de9302db64..b56e0561a6 100644 --- a/src/main/java/cyclops/control/ReaderWriterState.java +++ b/src/main/java/cyclops/control/ReaderWriterState.java @@ -18,8 +18,8 @@ public class ReaderWriterState { public static class µ { } - Monoid monoid; - BiFunction>> runState; + private final Monoid monoid; + private final BiFunction>> runState; public Tuple3 run(R r,S s) { return Fn0.run(runState.apply(r,s)); diff --git a/src/main/java/cyclops/free/FreePrograms.java b/src/main/java/cyclops/free/FreePrograms.java new file mode 100644 index 0000000000..f8821a4edb --- /dev/null +++ b/src/main/java/cyclops/free/FreePrograms.java @@ -0,0 +1,230 @@ +package cyclops.free; + +import cyclops.function.Fn3; +import cyclops.function.Fn4; +import cyclops.function.Fn5; +import org.jooq.lambda.tuple.*; + +import java.util.function.BiFunction; +import java.util.function.Function; + +/** + * Static for comprehensions for working with Free + */ +public interface FreePrograms { + public static Free forEach(Free free, + Function> value2, + Function, ? extends Free> value3, + Function, ? extends Free> value4, + Function, ? extends Free> value5, + Function, ? extends Free> value6, + Function, ? extends Free> value7, + Function, ? extends Free> value8 + ) { + + return free.flatMap(in -> { + + Free a = value2.apply(in); + return a.flatMap(ina -> { + Free b = value3.apply(Tuple.tuple(in,ina)); + return b.flatMap(inb -> { + + Free c = value4.apply(Tuple.tuple(in,ina,inb)); + + return c.flatMap(inc->{ + Free d = value5.apply(Tuple.tuple(in,ina,inb,inc)); + return d.flatMap(ind->{ + Free e = value6.apply(Tuple.tuple(in,ina,inb,inc,ind)); + return e.flatMap(ine->{ + Free f = value7.apply(Tuple.tuple(in,ina,inb,inc,ind,ine)); + return f.flatMap(inf->{ + Free g = value8.apply(Tuple.tuple(in,ina,inb,inc,ind,ine,inf)); + return g; + + }); + + }); + }); + + }); + + }); + + + }); + + + }); + + } + public static Free forEach(Free free, + Function> value2, + Function, ? extends Free> value3, + Function, ? extends Free> value4, + Function, ? extends Free> value5, + Function, ? extends Free> value6, + Function, ? extends Free> value7 + ) { + + return free.flatMap(in -> { + + Free a = value2.apply(in); + return a.flatMap(ina -> { + Free b = value3.apply(Tuple.tuple(in,ina)); + return b.flatMap(inb -> { + + Free c = value4.apply(Tuple.tuple(in,ina,inb)); + + return c.flatMap(inc->{ + Free d = value5.apply(Tuple.tuple(in,ina,inb,inc)); + return d.flatMap(ind->{ + Free e = value6.apply(Tuple.tuple(in,ina,inb,inc,ind)); + return e.flatMap(ine->{ + Free f = value7.apply(Tuple.tuple(in,ina,inb,inc,ind,ine)); + return f; + }); + }); + + }); + + }); + + + }); + + + }); + + } + + public static Free forEach(Free free, + Function> value2, + Function, ? extends Free> value3, + Function, ? extends Free> value4, + Function, ? extends Free> value5, + Function, ? extends Free> value6 + ) { + + return free.flatMap(in -> { + + Free a = value2.apply(in); + return a.flatMap(ina -> { + Free b = value3.apply(Tuple.tuple(in,ina)); + return b.flatMap(inb -> { + + Free c = value4.apply(Tuple.tuple(in,ina,inb)); + + return c.flatMap(inc->{ + Free d = value5.apply(Tuple.tuple(in,ina,inb,inc)); + return d.flatMap(ind->{ + Free e = value6.apply(Tuple.tuple(in,ina,inb,inc,ind)); + return e; + }); + }); + + }); + + + }); + + + }); + + } + public static Free forEach(Free free, + Function> value2, + Function, ? extends Free> value3, + Function, ? extends Free> value4, + Function, ? extends Free> value5 + + ) { + + return free.flatMap(in -> { + + Free a = value2.apply(in); + return a.flatMap(ina -> { + Free b = value3.apply(Tuple.tuple(in,ina)); + return b.flatMap(inb -> { + + Free c = value4.apply(Tuple.tuple(in,ina,inb)); + + return c.flatMap(inc->{ + Free d = value5.apply(Tuple.tuple(in,ina,inb,inc)); + return d; + }); + + }); + + + }); + + + }); + + } + public static Free forEach(Free free, + Function> value2, + Function, ? extends Free> value3, + Function, ? extends Free> value4 + + ) { + + return free.flatMap(in -> { + + Free a = value2.apply(in); + return a.flatMap(ina -> { + Free b = value3.apply(Tuple.tuple(in,ina)); + return b.flatMap(inb -> { + + Free c = value4.apply(Tuple.tuple(in,ina,inb)); + + return c; + + }); + + + }); + + + }); + + } + public static Free forEach(Free free, + Function> value2, + Function, ? extends Free> value3 + + ) { + + return free.flatMap(in -> { + + Free a = value2.apply(in); + return a.flatMap(ina -> { + Free b = value3.apply(Tuple.tuple(in,ina)); + return b; + + + }); + + + }); + + } + public static Free forEach(Free free, + Function> value2 + + + ) { + + return free.flatMap(in -> { + + Free a = value2.apply(in); + return a; + + + }); + + } + + + +} From 0424d22becbdd1b1316f253ebda9585c64f355bd Mon Sep 17 00:00:00 2001 From: John McClean Date: Wed, 15 Feb 2017 11:48:52 +0000 Subject: [PATCH 13/14] more tests, lazy persistent col constructors --- There | 0 .../extensions/lazy/LazyListX.java | 29 +--------------- .../extensions/lazy/immutable/LazyPBagX.java | 7 +++- .../lazy/immutable/LazyPOrderedSetX.java | 7 +++- .../lazy/immutable/LazyPQueueX.java | 7 +++- .../extensions/lazy/immutable/LazyPSetX.java | 7 +++- .../lazy/immutable/LazyPStackX.java | 7 +++- .../lazy/immutable/LazyPVectorX.java | 5 ++- src/main/java/cyclops/free/FreePrograms.java | 2 ++ src/test/java/cyclops/monads/KleisliTest.java | 34 +++++++++++++++++++ 10 files changed, 71 insertions(+), 34 deletions(-) delete mode 100644 There diff --git a/There b/There deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/main/java/com/aol/cyclops2/data/collections/extensions/lazy/LazyListX.java b/src/main/java/com/aol/cyclops2/data/collections/extensions/lazy/LazyListX.java index 0db8d912a5..0a092f737e 100644 --- a/src/main/java/com/aol/cyclops2/data/collections/extensions/lazy/LazyListX.java +++ b/src/main/java/com/aol/cyclops2/data/collections/extensions/lazy/LazyListX.java @@ -147,34 +147,7 @@ public LazyListX unitIterator(Iterator it) { } - public static void main(String[] args){ - - ReactiveSeq stream = ReactiveSeq.of(1,2,3); - stream.map(i->i*2).printOut(); - ReactiveSeq r2 = stream.map(i->i*2); - r2.map(i->i*100).zipWithIndex().printOut(); - r2.map(i->i*1000).zipWithIndex().printOut(); - /** - LazyListX l2 = new LazyListX<>(null,ReactiveSeq.of(1,2,3), Collectors.toList()); - l2.map(i->i*100).printOut(); - l2.map(i->i*1000).printOut(); -**/ - /** - // LazyListX list = new LazyListX<>(null,ReactiveSeq.of(1,2,3), Collectors.toList()); - LazyListX list = new LazyListX<>(Arrays.asList(1,2,3),null, Collectors.toList()); - - list.map(i->i*2).printOut(); - ListX l2 = list.map(i->i*2); - System.out.println(l2.getClass()); - list.map(i->i*3) - .peek(System.out::println) - .forEach(System.err::println); - - l2.map(i->i*100).printOut(); - System.out.println(l2.getClass() + " " + ((LazyListX)l2).getList()); - l2.map(i->i*1000).printOut(); -**/ - } + @Override public LazyListX unit(Collection col) { diff --git a/src/main/java/com/aol/cyclops2/data/collections/extensions/lazy/immutable/LazyPBagX.java b/src/main/java/com/aol/cyclops2/data/collections/extensions/lazy/immutable/LazyPBagX.java index 6bb171b2d8..4b0498ad10 100644 --- a/src/main/java/com/aol/cyclops2/data/collections/extensions/lazy/immutable/LazyPBagX.java +++ b/src/main/java/com/aol/cyclops2/data/collections/extensions/lazy/immutable/LazyPBagX.java @@ -1,9 +1,9 @@ package com.aol.cyclops2.data.collections.extensions.lazy.immutable; -import com.aol.cyclops2.data.collections.extensions.persistent.PersistentCollectionX; import cyclops.Reducers; import cyclops.collections.immutable.PBagX; +import cyclops.function.Reducer; import cyclops.stream.ReactiveSeq; import org.pcollections.PBag; @@ -47,6 +47,11 @@ public LazyPBagX(PBag list, ReactiveSeq seq) { super(list, seq, Reducers.toPBag()); + } + public LazyPBagX(PBag list, ReactiveSeq seq, Reducer> reducer) { + super(list, seq, reducer); + + } public LazyPBagX(PBag list) { super(list, null, Reducers.toPBag()); diff --git a/src/main/java/com/aol/cyclops2/data/collections/extensions/lazy/immutable/LazyPOrderedSetX.java b/src/main/java/com/aol/cyclops2/data/collections/extensions/lazy/immutable/LazyPOrderedSetX.java index c064db64d8..92f4689bee 100644 --- a/src/main/java/com/aol/cyclops2/data/collections/extensions/lazy/immutable/LazyPOrderedSetX.java +++ b/src/main/java/com/aol/cyclops2/data/collections/extensions/lazy/immutable/LazyPOrderedSetX.java @@ -2,8 +2,8 @@ import cyclops.Reducers; -import cyclops.collections.immutable.PBagX; import cyclops.collections.immutable.POrderedSetX; +import cyclops.function.Reducer; import cyclops.stream.ReactiveSeq; import org.pcollections.POrderedSet; @@ -47,6 +47,11 @@ public LazyPOrderedSetX(POrderedSet list, ReactiveSeq seq) { super(list, seq, Reducers.toPOrderedSet()); + } + public LazyPOrderedSetX(POrderedSet list, ReactiveSeq seq, Reducer> reducer) { + super(list, seq, reducer); + + } public LazyPOrderedSetX(POrderedSet list) { super(list, null, Reducers.toPOrderedSet()); diff --git a/src/main/java/com/aol/cyclops2/data/collections/extensions/lazy/immutable/LazyPQueueX.java b/src/main/java/com/aol/cyclops2/data/collections/extensions/lazy/immutable/LazyPQueueX.java index 6fd2756d5b..c984d43c5f 100644 --- a/src/main/java/com/aol/cyclops2/data/collections/extensions/lazy/immutable/LazyPQueueX.java +++ b/src/main/java/com/aol/cyclops2/data/collections/extensions/lazy/immutable/LazyPQueueX.java @@ -2,8 +2,8 @@ import cyclops.Reducers; -import cyclops.collections.immutable.PBagX; import cyclops.collections.immutable.PQueueX; +import cyclops.function.Reducer; import cyclops.stream.ReactiveSeq; import org.pcollections.PQueue; @@ -47,6 +47,11 @@ public LazyPQueueX(PQueue list, ReactiveSeq seq) { super(list, seq, Reducers.toPQueue()); + } + public LazyPQueueX(PQueue list, ReactiveSeq seq, Reducer> reducer) { + super(list, seq, reducer); + + } public LazyPQueueX(PQueue list) { super(list, null, Reducers.toPQueue()); diff --git a/src/main/java/com/aol/cyclops2/data/collections/extensions/lazy/immutable/LazyPSetX.java b/src/main/java/com/aol/cyclops2/data/collections/extensions/lazy/immutable/LazyPSetX.java index 9060235cca..1241be9d6c 100644 --- a/src/main/java/com/aol/cyclops2/data/collections/extensions/lazy/immutable/LazyPSetX.java +++ b/src/main/java/com/aol/cyclops2/data/collections/extensions/lazy/immutable/LazyPSetX.java @@ -2,8 +2,8 @@ import cyclops.Reducers; -import cyclops.collections.immutable.PBagX; import cyclops.collections.immutable.PSetX; +import cyclops.function.Reducer; import cyclops.stream.ReactiveSeq; import org.pcollections.PSet; @@ -47,6 +47,11 @@ public LazyPSetX(PSet list, ReactiveSeq seq) { super(list, seq, Reducers.toPSet()); + } + public LazyPSetX(PSet list, ReactiveSeq seq, Reducer> reducer) { + super(list, seq, reducer); + + } public LazyPSetX(PSet list) { super(list, null, Reducers.toPSet()); diff --git a/src/main/java/com/aol/cyclops2/data/collections/extensions/lazy/immutable/LazyPStackX.java b/src/main/java/com/aol/cyclops2/data/collections/extensions/lazy/immutable/LazyPStackX.java index 8f96a6c97b..b26f1f7dd0 100644 --- a/src/main/java/com/aol/cyclops2/data/collections/extensions/lazy/immutable/LazyPStackX.java +++ b/src/main/java/com/aol/cyclops2/data/collections/extensions/lazy/immutable/LazyPStackX.java @@ -2,8 +2,8 @@ import cyclops.Reducers; -import cyclops.collections.immutable.PBagX; import cyclops.collections.immutable.PStackX; +import cyclops.function.Reducer; import cyclops.stream.ReactiveSeq; import lombok.Getter; import org.pcollections.PStack; @@ -51,6 +51,11 @@ public LazyPStackX(PStack list, ReactiveSeq seq, boolean efficientOps) { super(list, seq, Reducers.toPStack()); this.efficientOps= efficientOps; + } + public LazyPStackX(PStack list, ReactiveSeq seq, boolean efficientOps, Reducer> reducer) { + super(list, seq, reducer); + this.efficientOps= efficientOps; + } public LazyPStackX(PStack list,boolean efficientOps) { super(list, null, Reducers.toPStack()); diff --git a/src/main/java/com/aol/cyclops2/data/collections/extensions/lazy/immutable/LazyPVectorX.java b/src/main/java/com/aol/cyclops2/data/collections/extensions/lazy/immutable/LazyPVectorX.java index c678ba980e..7d105d8865 100644 --- a/src/main/java/com/aol/cyclops2/data/collections/extensions/lazy/immutable/LazyPVectorX.java +++ b/src/main/java/com/aol/cyclops2/data/collections/extensions/lazy/immutable/LazyPVectorX.java @@ -2,8 +2,8 @@ import cyclops.Reducers; -import cyclops.collections.immutable.PBagX; import cyclops.collections.immutable.PVectorX; +import cyclops.function.Reducer; import cyclops.stream.ReactiveSeq; import org.pcollections.PVector; @@ -45,6 +45,9 @@ public LazyPVectorX(PVector list, ReactiveSeq seq) { super(list, seq, Reducers.toPVector()); + } + public LazyPVectorX(PVector list, ReactiveSeq seq, Reducer> reducer) { + super(list, seq, reducer); } public LazyPVectorX(PVector list) { super(list, null, Reducers.toPVector()); diff --git a/src/main/java/cyclops/free/FreePrograms.java b/src/main/java/cyclops/free/FreePrograms.java index f8821a4edb..09e9cfb050 100644 --- a/src/main/java/cyclops/free/FreePrograms.java +++ b/src/main/java/cyclops/free/FreePrograms.java @@ -12,6 +12,8 @@ * Static for comprehensions for working with Free */ public interface FreePrograms { + + public static Free forEach(Free free, Function> value2, Function, ? extends Free> value3, diff --git a/src/test/java/cyclops/monads/KleisliTest.java b/src/test/java/cyclops/monads/KleisliTest.java index af2d2e694e..a423c08538 100644 --- a/src/test/java/cyclops/monads/KleisliTest.java +++ b/src/test/java/cyclops/monads/KleisliTest.java @@ -1,9 +1,12 @@ package cyclops.monads; import cyclops.collections.ListX; +import cyclops.control.Xor; import cyclops.monads.Witness.stream; import cyclops.monads.Witness.reactiveSeq; import cyclops.stream.ReactiveSeq; +import org.jooq.lambda.tuple.Tuple; +import org.jooq.lambda.tuple.Tuple2; import org.junit.Test; import java.util.stream.Collectors; @@ -17,6 +20,37 @@ * Created by johnmcclean on 06/02/2017. */ public class KleisliTest { + @Test + public void firstK(){ + Kleisli k1 = t -> AnyM.fromArray(t); + assertThat(ListX.of(10), + equalTo(k1.firstK().apply(Tuple.tuple(10,-1)).reactiveSeq().map(Tuple2::v1).toList())); + } + + @Test + public void secondK(){ + Kleisli k1 = t -> AnyM.fromArray(t); + assertThat(ListX.of(-1), + equalTo(k1.secondK().apply(Tuple.tuple(10,-1)).reactiveSeq().map(Tuple2::v2).toList())); + } + @Test + public void leftK(){ + Kleisli k1 = t -> AnyM.fromArray(t); + assertThat(ListX.of(10), + equalTo(k1.leftK(stream.INSTANCE).apply(Xor.secondary(10)).reactiveSeq().map(Xor::secondaryGet).toList())); + } + @Test + public void rightK(){ + Kleisli k1 = t -> AnyM.fromArray(t); + assertThat(ListX.of(10), + equalTo(k1.rightK(stream.INSTANCE).apply(Xor.primary(10)).reactiveSeq().map(Xor::get).toList())); + } + @Test + public void andThen(){ + Kleisli k1 = t -> AnyM.fromArray(t); + assertThat("10",equalTo(k1.andThen(s->s.reactiveSeq() + .join()).apply(10))); + } @Test public void local(){ From 85bfb33eb2f17d2f1b04e749255695244f5db9ac Mon Sep 17 00:00:00 2001 From: John McClean Date: Wed, 15 Feb 2017 14:44:13 +0000 Subject: [PATCH 14/14] bump versions --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 73ee4bb796..846ee85d2b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version = 2.0.0-MI3 +version = 2.0.0-MI4 lombokVersion=1.16.12 joolVersion=0.9.12 pCollectionsVersion=2.1.2