Related
I have a discussion with colleague that we should not be using setters inside stream.map() like the solution suggested here - https://stackoverflow.com/a/35377863/1552771
There is a comment to this answer that discourages using map this way, but there hasn’t been a reason given as to why this is a bad idea. Can someone provide a possible scenario why this can break?
I have seen some discussions where people talk about concurrent modification of the collection itself, by adding or removing items from it, but are there any negatives to using map to just set some values to a data object?
Using side effects in map like invoking a setter, has a lot of similarities to using peek for non-debugging purposes, which have been discussed in In Java streams is peek really only for debugging?
This answer has a very good general advice:
Don't use the API in an unintended way, even if it accomplishes your immediate goal. That approach may break in the future, and it is also unclear to future maintainers.
Whereas the other answer names associated practical problems; I have to cite myself:
The important thing you have to understand, is that streams are driven by the terminal operation. The terminal operation determines whether all elements have to be processed or any at all.
When you place an operation with a side effect into a map function, you have a specific expectation about on which elements it will be performed and perhaps even how it will be performed, e.g. in which order. Whether the expectation will be fulfilled, depends on other subsequent Stream operations and perhaps even on subtle implementation details.
To show some examples:
IntStream.range(0, 10) // outcome changes with Java 9
.mapToObj(i -> System.out.append("side effect on "+i+"\n"))
.count();
IntStream.range(0, 2) // outcome changes with Java 10 (or 8u222)
.flatMap(i -> IntStream.range(i * 5, (i+1) * 5 ))
.map(i -> { System.out.println("side effect on "+i); return i; })
.anyMatch(i -> i > 3);
IntStream.range(0, 10) // outcome may change with every run
.parallel()
.map(i -> { System.out.println("side effect on "+i); return i; })
.anyMatch(i -> i > 6);
Further, as already mentioned in the linked answer, even if you have a terminal operation that processes all elements and is ordered, there is no guaranty about the processing order (or concurrency for parallel streams) of intermediate operations.
The code may happen to do the desired thing when you have a stream with no duplicates and a terminal operation processing all elements and a map function which is calling only a trivial setter, but the code has so many dependencies on subtle surrounding conditions that it will become a maintenance nightmare. Which brings us back to the first quote about using an API in an unintended way.
I think the real issue here is that it is just bad practice and violates the intended use of the capability. For example, one can also accomplish the same thing with filter. This perverts its use and also makes the code confusing or at best, unnecessarily verbose.
public static void main(String[] args) {
List<MyNumb> foo =
IntStream.range(1, 11).mapToObj(MyNumb::new).collect(
Collectors.toList());
System.out.println(foo);
foo = foo.stream().filter(i ->
{
i.value *= 10;
return true;
}).collect(Collectors.toList());
System.out.println(foo);
}
class MyNumb {
int value;
public MyNumb(int v) {
value = v;
}
public String toString() {
return Integer.toString(value);
}
}
So going back to the original example. One does not need to use map at all, resulting in the following rather ugly mess.
foos = foos.stream()
.filter(foo -> { boolean b = foo.isBlue();
if (b) {
foo.setTitle("Some value");
}
return b;})
.collect(Collectors.toList());
Streams are not just some new set of APIs which makes things easier for you. It also brings functional programming paradigm with it.
And, functional programming paradigm's most important aspect is to use pure functions for computations. A pure function is one where the output depends only and only on its input.
So, basically Streams API should use stateless, side-effect-free and pure functions.
Quoting things from Joshua Bloch's Effective Java (3rd Edition)
If you’re new to streams, it can be difficult to get the hang of them. Merely expressing your computation as a stream pipeline can be hard. When you succeed, your program will run, but you may realize little if any benefit. Streams isn’t just an API, it’s a paradigm based on functional programming. In order to obtain the expressiveness, speed, and in some cases parallelizability that streams have to offer, you have to adopt the paradigm as well as the API. The most important part of the streams paradigm is to structure your compu- tation as a sequence of transformations where the result of each stage is as close as possible to a pure function of the result of the previous stage. A pure function is one whose result depends only on its input: it does not depend on any mutable state, nor does it update any state. In order to achieve this, any function objects that you pass into stream operations, both intermediate and terminal, should be free of side-effects.
Occasionally, you may see streams code that looks like this snippet, which builds a frequency table of the words in a text file:
// Uses the streams API but not the paradigm--Don't do this!
Map<String, Long> freq = new HashMap<>();
try (Stream<String> words = new Scanner(file).tokens()) {
words.forEach(word -> { freq.merge(word.toLowerCase(), 1L, Long::sum);
});
}
What’s wrong with this code? After all, it uses streams, lambdas, and method references, and gets the right answer. Simply put, it’s not streams code at all; it’s iterative code masquerading as streams code. It derives no benefits from the streams API, and it’s (a bit) longer, harder to read, and less maintainable than the corresponding iterative code. The problem stems from the fact that this code is doing all its work in a terminal forEach operation, using a lambda that mutates external state (the frequency table). A forEach operation that does anything more than present the result of the computation performed by a stream is a “bad smell in code,” as is a lambda that mutates state. So how should this code look?
// Proper use of streams to initialize a frequency table
Map<String, Long> freq;
try (Stream<String> words = new Scanner(file).tokens()) {
freq = words
.collect(groupingBy(String::toLowerCase, counting()));
}
Just to name a few:
map() with setter is interfering (it modifies the initial data), while specs require a non-interfering function. For more details read this post.
map() with setter is stateful (your logic may depend on initial value of field you're updating), while specs require a stateless function
even if you're not interfering the collection that you're iterating over, the side effect of the setter is unnecessary
Setters in map may mislead the future code maintainers
etc...
I am currently trying to wrap my head around typeclasses and instances and I don't quite understand the point of them yet. I have two questions on the matter so far:
1) Why is it necessary to have a type class in a function signature when the function uses some function from that type class. Example:
f :: (Eq a) => a -> a -> Bool
f a b = a == b
Why put (Eq a) in the signature. If == is not defined for a then why not just throw the error when encountering a == b? What is the point in having to declare the type class ahead?
2) How are type classes and function overloading related?
It is not possible to do this:
data A = A
data B = B
f :: A -> A
f a = a
f :: B -> B
f b = b
But it is possible to do this:
data A = A
data B = B
class F a where
f :: a -> a
instance F A where
f a = a
instance F B where
f b = b
What is up with that? Why can't I have two functions with the same name but operating on different types... Coming from C++ I find that very strange. But I probably have wrong conceptions about what these things really are. but once I wrap them in these type class instance thingies I can.
Feel free to hurl category or type theoretical words at me as well, as I am learning about these subjects in parallel to learning Haskell and I suspect there is a theoretical basis in these for how Haskell does things here.
I agree with much of Willem Van Onsem’s answer, but I think it overlooks one of the principal advantages of typeclasses over truly ad-hoc overloading: abstraction. Imagine we used ad-hoc overloading instead of typeclasses to define the Monad operations:
-- Maybe
pure :: a -> Maybe a
pure = Just
(>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b
Just x >>= f = f x
Nothing >>= _ = Nothing
-- Either
pure :: a -> Either e a
pure = Right
(>>=) :: Either e a -> (a -> Either e b) -> Either e b
Right x >>= f = f x
Left err >>= _ = Left err
Now, we know that every monad can be expressed in terms of pure and >>=, as above, but we also know that they can be equivalently expressed using fmap, pure, and join. Therefore, we should be able to implement a join function that works on any monad:
join x = x >>= id
However, now we have a problem. What is join’s type?
Clearly, join has to be polymorphic, since it works on any monad by design. But giving it the type signature forall m a. m (m a) -> m a would obviously be wrong, since it doesn’t work for all types, only monadic ones. Therefore, we need something in our type that expresses the need for the existence of some operation (>>=) :: m a -> (a -> m b) -> m b, which is exactly what the typeclass constraint provides.
Given this, it becomes clear that ad-hoc overloading makes it possible to overload names, but it is impossible to abstract over those overloaded names because there is no guarantee the different implementations are related in any way. You could define monads without typeclasses, but then you couldn’t define join, when, unless, mapM, sequence, and all the other nice things that you get for free when you define just two operations.
Therefore, typeclasses are necessary in Haskell to enable code reuse and to avoid enormous amounts of duplication. But could you have both typeclass-style overloading and type-directed, ad-hoc name overloading? Yes, and in fact, Idris does. But Idris’s type inference is very different from Haskell’s, so it’s more feasible to support than it is in Haskell for many of the reasons in Willem’s answer.
In short: because that is how Haskell was designed.
Why put (Eq a) in the signature. If == is not defined for a then why not just throw the error when encountering a == b?
Why do we put the types in the signature of a C++ program (and not just somewhere as an assertion in the body)? Because that is how C++ is designed. Typically a concept on what programming languages are built is "make explicit what needs to be explicit".
It is not said that a Haskell module is open-source. So that means we only have the signature available. It would thus mean that when we for instance write:
Prelude> foo A A
<interactive>:4:1: error:
• No instance for (Eq A) arising from a use of ‘foo’
• In the expression: foo A A
In an equation for ‘it’: it = foo A A
We would frequently write foo here with types that have no Eq typeclass. As a result, we would get a lot of errors that are only discovered at compile time (or if Haskell was a dynamic language, at runtime). The idea of putting Eq a in the type signature is that we can look up the signature of foo in advance, and thus ensure that the types are instance of the typeclass.
Note that you do not have to write type signatures yourself: Haskell can typically derive the signature of a function, but a signature should include all the necessary information to call and use a function effectively. By adding type constraints, we speed up development.
What is up with that? Why can't I have two functions with the same name but operating on different types.
Again: that is how Haskell is designed. Functions in functional programming languages are "first class citizens". It means these usually have a name and we want to avoid name clashes as much as possible. Just like classes in C++ typically have a unique name (except for namespaces).
Say you would define two different functions:
incr :: Int -> Int
incr = (+1)
incr :: Bool -> Bool
incr _ = True
bar = incr
Then which incr would bar have to select? Of course we can make the types explicit (i.e. incr :: Bool -> Bool), but usually we want to avoid that work, since it introduces a lot of noise.
Another good reason why we do not do that, is because typically a typeclass is not just a collection of functions: it adds contracts to these functions. For instance the Monad typeclass has to satisfy certain relations between the functions. For example (>>= return) should be equivalent with id. In other words, the typeclass:
class Monad m where
(>>=) :: m a -> (a -> m b) -> m b
return :: a -> m a
Does not describes two independent functions (>>=) and return: this is a set of functions. You have them both (usually with some contracts between the specific >>= and return), or none of these at all.
This only answers question 1 (directly, at least).
The type signature f :: a -> a -> Bool is shorthand for f :: forall a. a -> a -> Bool. f would not truly work for all types a if it only works for as that have (==) defined. This restriction to types that have (==) is expressed using the constraint (Eq a) in f :: forall a. (Eq a) => a -> a -> Bool.
"For all"/universal quantification is at the core of Haskell's (parametric) polymorphism and, among other things, provides the powerful and important properties of parametricity.
Haskell holds to two axioms (among others):
Every variable is useable as an expression in its own right;
Every expression has a type that precisely specifies what you are allowed to do with it.
If you had
f :: A -> A
and
f :: B -> B
then, according to the principles adopted in Haskell, f would still be a valid expression, on its own which would still have to have a single type. While it's possible to do that using subtyping, it was deemed much more complicated than the type-class solution.
Similarly, the need for Eq a in
(==) :: Eq a => a -> a -> Bool
comes from the fact that the type of == has to completely describe what you can do with it. If you can only call it at certain types, the type signature has to reflect that.
I try to learn about good practices in programming and I'm stuck with this question. I know that in Java, recursive functions can be 'a pain in the ass' (sometimes), and I try to implement as much as I can the tail version of that function. Is it worth bothering with this or should I do in the old fashioned way?
Is there any difference between this two functions (in Kotlin):
tailrec fun tail_fibonacci(n : BigInteger, fib1 : BigInteger = BigInteger.ZERO , fib2 : BigInteger = BigInteger.ONE) :
BigInteger {
return when(n){
BigInteger.ZERO -> fib1
else -> tail_fibonacci(n.minus(BigInteger.ONE),fib1.plus(fib2),fib1)
}
}
fun iterative_fibonacci(n: BigInteger) : BigInteger {
var count : BigInteger = BigInteger.ONE
var a : BigInteger = BigInteger.ZERO
var b : BigInteger = BigInteger.ONE
var c : BigInteger
while(count < n){
count += BigInteger.ONE
c = a + b
a = b
b = c
}
return b
}
The biggest difference I see is the signatures: while iterative_fibonacci takes one argument and is quite clear, tail_fibonacci takes three, and though the defaults are provided, this might surprise the user. You can, however, make a wrapper function for it, and even make the tailrec function a local one.
There should not be much difference in the resulting bytecode the two functions are compiled to, except for n.minus(BigInteger.ONE) vs count += BigInteger.ONE, and you can check it for yourself with a Kotlin bytecode viewer.
Regarding performance, there should not be any predictable difference between the two implementations (also note that the JVM additionally optimizes the code at runtime with JIT compiler), but of course the tailrec function is much more efficient than an ordinary recursive one would be.
As to the code style (which is highly opinion-based), many tail-recursive solutions look more natural (and closer to math notation), and some do not (e.g. when there are many parameters that end up in a complete mess).
So, I think, tailrec should be used as a performance tool (and especially as a way to avoid stack overflow, which requires all recursive calls to be tail ones) when you find a recursive definition more suitable for expressing what the code does.
They are equivalent in terms of performance. Kotlin will optimize the recursion on tailrec functions, meaning it is identical to a loop based approach.
Whether you should prefer a functional or iterative approach really comes down to your own preference (and your team's, if applicable), taking into account readability, conciseness, and intuitiveness. This judgement may change from method to method; one function might be more readable using a functional approach, where another might benefit from a straightforward loop.
The nice thing about Kotlin is that it supports both approaches, and allows a developer to use the tool they need for the job.
I am wondering, is any nice way (if it is possible at all) to implement an alpha-equivalence comparison in Java-8?
Obviously these two lambda-s are alpha-equivalent. Let us suppose that for some circumstances we want to detect this fact. How it can be achieved?
Predicate<Integer> l1 = x -> x == 1;
Predicate<Integer> l2 = y -> y == 1;
I'm going out on a limb with this answer, but it may be worth mentioning this:
There is no way to do this. As Brian Goetz pointed out in an answer to a related question, there are no specified, reliable ways of obtaining the "contents" of a lambda, in that sense.
But (and now comes the vague, handwaving part) :
There is no way to do this yet.
It might be possible to do this in the future. Maybe not with Java 9, but later. The Project Panama has ambituous goals, among them, giving the developer a deeper access to lambdas, aiding in further (runtime) optimizations, translations and processing.
And recently, Radosław Smogura posted in the mailing list :
I try to capture lambda expression to get them as expression tree during runtime. I’m able to do it for simple lambdas like (o) -> (var == var) && ((varX == varX) && (someField + 1 == 1)), so later user can use (missing) API to examine tree.
Right now tree can be accessed with code like this:
Method m = BasicMatadataTest.class.getDeclaredMethod("lambda$meta0");
Expression e = (Expression) m.invoke(null);
BinaryExpression top = (BinaryExpression) e;
BinaryExpression vars = (BinaryExpression) top.getLefthandExpression(); // represents (var == var)
(VariableExpression) vars.getLefthandExpression() // represents first var, and it’s reference equal to vars.getRighthandExpression() as it’s same variable
...
The key point here may be the comment:
represents first var, and it’s reference equal to vars.getRighthandExpression() as it’s same variable
(e.b.m)
So if I understood your question and this mailing list post correctly, then it might be possible to determine the equivalence between such expressions: Comparing the tree structure would be fairly trivial (given the functionality sketched above). And then it might boil down to treating two VariableExpression as being "equal", regardless of the actual variable name.
The mailing list message points to the repositories:
https://bitbucket.org/radoslaw_smogura/java-lambda-metaexpression-jdk9-langtools/branch/metaexpr
https://bitbucket.org/radoslaw_smogura/java-lambda-metaexpresions-jdk/commits/branch/metaexpr
(Disclaimer: I have not tested this, and don't know how to get this running (or whether it works at all) - but to my understanding, it is at least very close to what the question was actually about).
In the interests of helping to understand what a monad is, can someone provide an example using java ? Are they possible ?
Lambda expressions are possible using java if you download the pre-release lambda compatible JDK8 from here http://jdk8.java.net/lambda/
An example of a lambda using this JDK is shown below, can someone provide a comparably simple monad ?
public interface TransformService {
int[] transform(List<Integer> inputs);
}
public static void main(String ars[]) {
TransformService transformService = (inputs) -> {
int[] ints = new int[inputs.size()];
int i = 0;
for (Integer element : inputs) {
ints[i] = element;
}
return ints;
};
List<Integer> inputs = new ArrayList<Integer>(5) {{
add(10);
add(10);
}};
int[] results = transformService.transform(inputs);
}
Just FYI:
The proposed JDK8 Optional class does satisfy the three Monad laws. Here's a gist demonstrating that.
All it takes be a Monad is to provide two functions which conform to three laws.
The two functions:
Place a value into monadic context
Haskell's Maybe: return / Just
Scala's Option: Some
Functional Java's Option: Option.some
JDK8's Optional: Optional.of
Apply a function in monadic context
Haskell's Maybe: >>= (aka bind)
Scala's Option: flatMap
Functional Java's Option: flatMap
JDK8's Optional: flatMap
Please see the above gist for a java demonstration of the three laws.
NOTE: One of the key things to understand is the signature of the function to apply in monadic context: it takes the raw value type, and returns the monadic type.
In other words, if you have an instance of Optional<Integer>, the functions you can pass to its flatMap method will have the signature (Integer) -> Optional<U>, where U is a value type which does not have to be Integer, for example String:
Optional<Integer> maybeInteger = Optional.of(1);
// Function that takes Integer and returns Optional<Integer>
Optional<Integer> maybePlusOne = maybeInteger.flatMap(n -> Optional.of(n + 1));
// Function that takes Integer and returns Optional<String>
Optional<String> maybeString = maybePlusOne.flatMap(n -> Optional.of(n.toString));
You don't need any sort of Monad Interface to code this way, or to think this way. In Scala, you don't code to a Monad Interface (unless you are using Scalaz library...). It appears that JDK8 will empower Java folks to use this style of chained monadic computations as well.
Hope this is helpful!
Update: Blogged about this here.
Java 8 will have lambdas; monads are a whole different story. They are hard enough to explain in functional programming (as evidenced by the large number of tutorials on the subject in Haskell and Scala).
Monads are a typical feature of statically typed functional languages. To describe them in OO-speak, you could imagine a Monad interface. Classes that implement Monad would then be called 'monadic', provided that in implementing Monad the implementation obeys what are known as the 'monad laws'. The language then provides some syntactic sugar that makes working with instances of the Monad class interesting.
Now Iterable in Java has nothing to do with monads, but as a example of a type that the Java compiler treats specially (the foreach syntax that came with Java 5), consider this:
Iterable<Something> things = getThings(..);
for (Something s: things) { /* do something with s */ }
So while we could have used Iterable's Iterator methods (hasNext and company) in an old-style for loop, Java grants us this syntactic sugar as a special case.
So just as classes that implement Iterable and Iterator must obey the Iterator laws (Example: hasNext must return false if there is no next element) to be useful in foreach syntax - there would exist several monadic classes that would be useful with a corresponding do notation (as it is called in Haskell) or Scala's for notation.
So -
What are good examples of monadic classes?
What would syntactic sugar for dealing with them look like?
In Java 8, I don't know - I am aware of the lambda notation but I am not aware of other special syntactic sugar, so I'll have to give you an example in another language.
Monads often serve as container classes (Lists are an example). Java already has java.util.List which is obviously not monadic, but here is Scala's:
val nums = List(1, 2, 3, 4)
val strs = List("hello", "hola")
val result = for { // Iterate both lists, return a resulting list that contains
// pairs of (Int, String) s.t the string size is same as the num.
n <- nums
s <- strs if n == s.length
} yield (n, s)
// result will be List((4, "hola"))
// A list of exactly one element, the pair (4, "hola")
Which is (roughly) syntactic sugar for:
val nums = List(1, 2, 3, 4)
val strs = List("hello", "hola")
val results =
nums.flatMap( n =>
strs.filter(s => s.size == n). // same as the 'if'
map(s => (n, s)) // Same as the 'yield'
)
// flatMap takes a lambda as an argument, as do filter and map
//
This shows a feature of Scala where monads are exploited to provide list comprehensions.
So a List in Scala is a monad, because it obeys Scala's monad laws, which stipulate that all monad implementations must have conforming flatMap, map and filter methods (if you are interested in the laws, the "Monads are Elephants" blog entry has the best description I've found so far). And, as you can see, lambdas (and HoF) are absolutely necessary but not sufficient to make this kind of thing useful in a practical way.
There's a bunch of useful monads besides the container-ish ones as well. They have all kinds of applications. My favorite must be the Option monad in Scala (the Maybe monad in Haskell), which is a wrapper type which brings about null safety: the Scala API page for the Option monad has a very simple example usage: http://www.scala-lang.org/api/current/scala/Option.html
In Haskell, monads are useful in representing IO, as a way of working around the fact that non-monadic Haskell code has indeterminate order of execution.
Having lambdas is a first small step into the functional programming world; monads
require both the monad convention and a large enough set of usable monadic types, as well as syntactic sugar to make working with them fun and useful.
Since Scala is arguably the language closest to Java that also allows (monadic) Functional Programming, do look at this Monad tutorial for Scala if you are (still) interested:
http://james-iry.blogspot.jp/2007/09/monads-are-elephants-part-1.html
A cursory googling shows that there is at least one attempt to do this in Java: https://github.com/RichardWarburton/Monads-in-Java -
Sadly, explaining monads in Java (even with lambdas) is as hard as explaining full-blown Object oriented programming in ANSI C (instead of C++ or Java).
Even though monads can be implemented in Java, any computation involving them is doomed to become a messy mix of generics and curly braces.
I'd say that Java is definitely not the language to use in order to illustrate their working or to study their meaning and essence. For this purpose it is far better to use JavaScript or to pay some extra price and learn Haskell.
Anyway, I am signaling you that I just implemented a state monad using the new Java 8 lambdas. It's definitely a pet project, but it works on a non-trivial test case.
You may find it presented at my blog, but I'll give you some details here.
A state monad is basically a function from a state to a pair (state,content). You usually give the state a generic type S and the content a generic type A.
Because Java does not have pairs we have to model them using a specific class, let's call it Scp (state-content pair), which in this case will have generic type Scp<S,A> and a constructor new Scp<S,A>(S state,A content). After doing that we can say that the monadic function will have type
java.util.function.Function<S,Scp<S,A>>
which is a #FunctionalInterface. That's to say that its one and only implementation method can be invoked without naming it, passing a lambda expression with the right type.
The class StateMonad<S,A> is mainly a wrapper around the function. Its constructor may be invoked e.g. with
new StateMonad<Integer, String>(n -> new Scp<Integer, String>(n + 1, "value"));
The state monad stores the function as an instance variable. It is then necessary to provide a public method to access it and feed it the state. I decided to call it s2scp ("state to state-content pair").
To complete the definition of the monad you have to provide a unit (aka return) and a bind (aka flatMap) method. Personally I prefer to specify unit as static, whereas bind is an instance member.
In the case of the state monad, unit gotta be the following:
public static <S, A> StateMonad<S, A> unit(A a) {
return new StateMonad<S, A>((S s) -> new Scp<S, A>(s, a));
}
while bind (as instance member) is:
public <B> StateMonad<S, B> bind(final Function<A, StateMonad<S, B>> famb) {
return new StateMonad<S, B>((S s) -> {
Scp<S, A> currentPair = this.s2scp(s);
return famb(currentPair.content).s2scp(currentPair.state);
});
}
You notice that bind must introduce a generic type B, because it is the mechanism that allows the chaining of heterogeneous state monads and gives this and any other monad the remarkable capability to move the computation from type to type.
I'd stop here with the Java code. The complex stuff is in the GitHub project. Compared to previous Java versions, lambdas remove a lot of curly braces, but the syntax is still pretty convoluted.
Just as an aside, I'm showing how similar state monad code may be written in other mainstream languages. In the case of Scala, bind (which in that case must be called flatMap) reads like
def flatMap[A, B](famb: A => State[S, B]) = new State[S, B]((s: S) => {
val (ss: S, aa: A) = this.s2scp(s)
famb(aa).s2scp(ss)
})
whereas the bind in JavaScript is my favorite; 100% functional, lean and mean but -of course- typeless:
var bind = function(famb){
return state(function(s) {
var a = this(s);
return famb(a.value)(a.state);
});
};
<shameless>
I am cutting a few corners here, but if you are interested in the details you will find them on my WP blog.</shameless>
Here's the thing about monads which is hard to grasp: monads are a
pattern, not a specific type. Monads are a shape, they are an abstract
interface (not in the Java sense) more than they are a concrete data
structure. As a result, any example-driven tutorial is doomed to
incompleteness and failure.
[...]
The only way to understand monads is to see them for what they are: a mathematical construct.
Monads are not metaphors by Daniel Spiewak
Monads in Java SE 8
List monad
interface Person {
List<Person> parents();
default List<Person> greatGrandParents1() {
List<Person> list = new ArrayList<>();
for (Person p : parents()) {
for (Person gp : p.parents()) {
for (Person ggp : p.parents()) {
list.add(ggp);
}
}
}
return list;
}
// <R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper)
default List<Person> greatGrandParents2() {
return Stream.of(parents())
.flatMap(p -> Stream.of(p.parents()))
.flatMap(gp -> Stream.of(gp.parents()))
.collect(toList());
}
}
Maybe monad
interface Person {
String firstName();
String middleName();
String lastName();
default String fullName1() {
String fName = firstName();
if (fName != null) {
String mName = middleName();
if (mName != null) {
String lName = lastName();
if (lName != null) {
return fName + " " + mName + " " + lName;
}
}
}
return null;
}
// <U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper)
default Optional<String> fullName2() {
return Optional.ofNullable(firstName())
.flatMap(fName -> Optional.ofNullable(middleName())
.flatMap(mName -> Optional.ofNullable(lastName())
.flatMap(lName -> Optional.of(fName + " " + mName + " " + lName))));
}
}
Monad is a generic pattern for nested control flow encapsulation.
I.e. a way to create reusable components from nested imperative idioms.
Important to understand that a monad is not just a generic wrapper class with a flat map operation.
For example, ArrayList with a flatMap method won't be a monad.
Because monad laws prohibit side effects.
Monad is a formalism. It describes the structure, regardless of content or meaning.
People struggle with relating to meaningless (abstract) things.
So they come up with metaphors which are not monads.
See also:
conversation between Erik Meijer and Gilad Bracha.
the only way to understand monads is by writing a bunch of combinator libraries, noticing the resulting duplication, and then discovering for yourself that monads let you factor out this duplication. In discovering this, everyone builds some intuition for what a monad is… but this intuition isn’t the sort of thing that you can communicate to someone else directly – it seems everyone has to go through the same experience of generalizing to monads from some concrete examples of combinator libraries. however
here i found some materials to learn Mondas.
hope to be useful for you too.
codecommit
james-iry.blogspot
debasishg.blogspot
This blog post gives a step-by-step example of how you might implement a Monad type (interface) in Java and then use it to define the Maybe monad, as a practical application.
This post explains that there is one monad built into the Java language, emphasising the point that monads are more common than many programmers may think and that coders often inadvertently reinvent them.
Despite all controversy about Optional satisfying, or not, the Monad laws, I usually like to look at Stream, Optional and CompletableFuture in the same way. In truth, all them provide a flatMap() and that is all I care and let me embrace the "the tasteful composition of side effects" (cited by Erik Meijer). So we may have corresponding Stream, Optional and CompletableFuture in the following way:
Regarding Monads, I usually simplify it only thinking on flatMap()(from "Principles of Reactive Programming" course by Erik Meijer):
A diagram for the "Optional" Monad in Java.
Your task: Perform operations on the "Actuals" (left side) transforming elements of type T union null to type U union null using the function in the light blue box (the light blue box function). Just one box is shown here, but there may be a chain of the light blue boxes (thus proceeding from type U union null to type V _union null to type W union null etc.)
Practically, this will cause you to worry about null values appearing in the function application chain. Ugly!
Solution: Wrap your T into an Optional<T> using the light green box functions, moving to the "Optionals" (right side). Here, transform elements of type Optional<T> to type Optional<U> using the red box function. Mirroring the application of functions to the "Actuals", there may be several red box functions to be be chained (thus proceeding from type Optional<U> to Optional<V> then to Optional<W> etc.). In the end, move back from the "Optionals" to the "Actuals" through one of the dark green box functions.
No worrying about null values anymore. Implementationwise, there will always be an Optional<U>, which may or may not be empty. You can chain the calls to to the red box functions without null checks.
The key point: The red box functions are not implemented individually and directly. Instead, they are obtained from the blue box functions (whichever have been implemented and are available, generally the light blue ones) by using either the map or the flatMap higher-order functions.
The grey boxes provide additional support functionality.
Simples.
I like to think of monads in slighlty more mathematical (but still informal) fashion. After that I will explain the relationship to one of Java 8's monads CompletableFuture.
First of all, a monad M is a functor. That is, it transforms a type into another type: If X is a type (e.g. String) then we have another type M<X> (e.g. List<String>). Moreover, if we have a transformation/function X -> Y of types, we should get a function M<X> -> M<Y>.
But there is more data to such a monad. We have a so-called unit which is a function X -> M<X> for each type X. In other words, each object of X can be wrapped in a natural way into the monad.
The most characteristic data of a monad, however, is it's product: a function M<M<X>> -> M<X> for each type X.
All of these data should satisfy some axioms like functoriality, associativity, unit laws, but I won't go into detail here and it also doesn't matter for practical usage.
We can now deduce another operation for monads, which is often used as an equivalent definition for monads, the binding operation: A value/object in M<X> can be bound with a function X -> M<Y> to yield another value in M<Y>. How do we achieve this? Well, first we apply functoriality to the function to obtain a function M<X> -> M<M<Y>>. Next we apply the monadic product to the target to obtain a function M<X> -> M<Y>. Now we can plug in the value of M<X> to obtain a value in M<Y> as desired. This binding operation is used to chain several monadic operations together.
Now lets come to the CompletableFuture example, i.e. CompletableFuture = M. Think of an object of CompletableFuture<MyData> as some computation that's performed asynchronously and which yields an object of MyData as a result some time in the future. What are the monadic operations here?
functoriality is realized with the method thenApply: first the computation is performed and as soon as the result is available, the function which is given to thenApply is applied to transform the result into another type
the monadic unit is realized with the method completedFuture: as the documentation tells, the resulting computation is already finished and yields the given value at once
the monadic product is not realized by a function, but the binding operation below is equivalent to it (together with functoriality) and its semantic meaning is simply the following: given a computation of type CompletableFuture<CompletableFuture<MyData>> that computation asynchronously yields another computation in CompletableFuture<MyData> which in turn yields some value in MyData later on, so performing both computations on after the other yields one computation in total
the resulting binding operation is realized by the method thenCompose
As you see, computations can now be wrapped up in a special context, namely asynchronicity. The general monadic structures enable us to chain such computations in the given context. CompletableFuture is for example used in the Lagom framework to easily construct highly asynchronous request handlers which are transparently backed up by efficient thread pools (instead of handling each request by a dedicated thread).
Haskell monads is an interface which specify rules to convert “datatype that is wrapped in another datatype” to another “datatype that is wrapped in another or same datatype”; the conversion steps is specified by a function you define with a format.
The function format takes a datatype and return “datatype that is wrapped in another datatype”. You can specify operations/ calculations during conversion e.g. multiply or lookup something.
It is so difficult to understand because of the nested abstraction. It is so abstracted so that you can reuse the rules to convert datatype in a datatype without custom programming to unwrap the first “ datatype that is wrapped in another datatype” before putting the data to your specified function; Optional with some datatype is an example of “datatype in a datatype”.
The specified function is any lambda confirming the format.
You don’t need to fully understand it; you will write your own reusable interface to solve similar problem. Monad is just exist because some mathematicians already hit and resolve that problem, and create monad for you to reuse. But due to its abstraction, it is difficult to learn and reuse in the first place.
In other words, e.g. Optional is a wrapper class, but some data is wrapped , some not, some function take wrapped data type but some don’t, return type can be of type wrapped or not. To chain calling mixture of function which may wrap or not in parameter/return types, you either do your own custom wrap/unwrap or reuse pattern of functor / applicative / monad to deal with all those wrapped/unwrapped combinations of chained function call. Every time u try to put optional to a method that only accept plain value and return optional, the steps are what monad does.