-
-
Notifications
You must be signed in to change notification settings - Fork 616
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
For Comprehensions #68
Comments
Another example using multiple generators: Haskell: Javaslang:
or |
Dependent generators: Haskell: Javaslang:
or |
Another example using more than two dependent generators: Haskell: Javaslang:
or |
Applications of comprehensions: list concatenation Haskell: concat :: [[a]] -> [a]
concat xss = [x | xs <- xss, x <- xs] Example: > concat [[1,2,3],[4,5],[6]]
[1,2,3,4,5,6] Javaslang: final List<List<Integer>> xss = List.of(List.of(1,2,3), List.of(4,5), List.of(6));
Gen.of(xss).flatMap(xs -> Gen.of(xs)).toList();
// in this case the same as
xss.flatMap(xs -> xs);
// or just
xss.flatten(); |
I've been thinking about this and I find the following syntax nicer then the initial proposed one. Haskell: Javaslang: This could even be taken a little bit further by adding a predicate. Javaslang: Or if you want to produce a List of a different type then the initial type of the input list: Javaslang: The comprehend method could also be an instance method of javaslang.collection.List
|
I like your suggestion! Do you want to contribute it? :-) |
Sure! |
May I ask a few questions?
Exactly the same as ` list.filter(x -> x < 10).map(x -> String.valueOf(x * x)); am I missing something?
I haven't found a way to do that in a more functional way, I wish list comprehensions can transform this into something like
Can that be made? I was expecting an API that accept Iterables and java.util.Stream, so we can use comprehend old java.util.List without pain. Something like
I know that expanding this to 1-to-8-arity and accept every combination of javaslang.List, java.util.Iterable, java.util.Stream and javaslang.Stream would be pretty much imposible without code generation, but it would be so nice to be able to write
Anyway, thanks for the wonderful job! |
@pablogrisafi1975 Hi, thank you for your great suggestions! I think you are right. The proposed list-comprehension API is similar to implement it directly. I'm planning to create for-comprehensions (from Scala) instead of list-comprehensions (from Haskell). It will look like this For(
interable_1,
...,
iterable_n
).yield(
(param_1, ..., param_n) -> ...
); If the iterable_k is a Javaslang collection, we may also filter (similar to if-guards in Scala): For(
iterable_1.filter(condition_1),
...,
iterable_n.filter(condition_n)
).yield(
(param_1, ..., param_n) -> ...
); Note: Option, Try, Future et al. are also Iterable and will work nice with this approach. We need a static |
I push this to 2.0.0 because this will be a quick win and code generation goes along with #1087 |
@jonasgeiregat I think we will move from List comprehensions to For comprehensions as described above. @pablogrisafi1975 is right, the Haskell term List.rangeClosed(1, 5).map(x -> x * x); and myList.filter(x -> x < 10).map(x -> x * x); I will change the name of this issue to There is one remaining question: What is the result type of the For comprehension? |
In Scala the For comprehension operates on filter-monadic types. Internally a for-call is translated to a cascade of If we use Iterables, this is not possible. We could
However, finally the results need to be flattened then. |
Maybe I'm missing something, but isn't the 'natural' return type a Am I suggesting Stream Comprenhensions....? |
Maybe event better would be a specific |
We should do it the Scala way. Everyone has this in mind when it comes to for-comprehensions: for {
a_1 <- filterMonadic_1
a_2 <- filterMonadic_2
...
a_n <- filterMonadic_n
} yield (a_1, a_2, ..., a_n) => ... which is just syntactic sugar for filterMonadic_1.flatMap(a_1 =>
filterMonadic_2.flatMap(a_2 =>
...
filterMonadic_n.map(a_n => ...)...)); I will think about it. |
We need to ship 2.0.0 - will bump that to 2.0.1. |
I've spent a while thinking about For-comprehensions. A full-blown solution would provide this:
I was yet not able to figure out a clean and concise way to express the above with Java. However, this should not be a reason to abandon syntactic sugar for cascaded iteration over multiple iterables. Therefore I prefer a pragmatic solution.
Please note that The interesting part is to define a javaslang.collection.Iterator that iterates over the following cross product: iterable_1 X iterable_2 X ... X iterable_m |
The implementation will look like this: public interface API {
static <T1> For1<T1> For(Iterable<T1> ts1) {
return new For1<>(Stream.ofAll(ts1));
}
static <T1, T2> For2<T1, T2> For(Iterable<T1> ts1, Iterable<T2> ts2) {
return new For2<>(Stream.ofAll(ts1), Stream.ofAll(ts2));
}
class For1<T> {
Stream<T> stream1;
For1(Stream<T> stream1) {
this.stream1 = stream1;
}
<R> Stream<R> yield(Function<? super T, ? extends R> f) {
return stream1.map(f);
}
}
class For2<T1, T2> {
Stream<T1> stream1;
Stream<T2> stream2;
For2(Stream<T1> stream1, Stream<T2> stream2) {
this.stream1 = stream1;
this.stream2 = stream2;
}
<R> Stream<R> yield(BiFunction<? super T1, ? super T2, ? extends R> f) {
return stream1.flatMap(t1 -> stream2.map(t2 -> f.apply(t1, t2)));
}
}
} |
Low hanging fruits - I will write the code generator now... |
Works like a charm: import static javaslang.API.*;
...
Stream<String> result = For(
Option.of(1),
Stream.of("a", "b", "c"),
List.of('ä', 'ö', 'ü')
).yield((i, s, c) -> i + s + c);
// [1aä, 1aö, 1aü, 1bä, 1bö, 1bü, 1cä, 1cö, 1cü]
System.out.println(result.toJavaList()); I will add tests and merge it into master. |
@pablogrisafi1975 @jonasgeiregat thanks for your assistance. I think this feature is really helpful! See #1128 for details on usage. |
Excellent! |
Yes, it is the convergence of languages. Martin Odersky's free online course Functional Programming Principles in Scala is one of the best learning resources for modern and advanced programming I know - especially for Java developers. |
Haskell:
[x^2 | x <- [1..5]]
-- produces
[1,4,9,16,25]
Javaslang:
Gen.range(1,5).map(x -> x*x).toList()
or
Haskell.eval("[x^2 | x <- [1..5]]").asList()
The text was updated successfully, but these errors were encountered: