Categories
Uncategorized

Application Monad in the actual development of

All journal authors, in any form reproduced please contact the author.
    Author: tison (from watercress)
    Source: https: //www.douban.com/note/733279598/

Application Monad in the actual development of

Different people will never like the contact angle Monad. Most online tutorials and presentations are starting from its strict definition, plus a few toy examples to explain when finished. Indeed, many fans are forms of logic FP fans or strong in math, but my understanding of the Monad is not defined by its entry. Instead, I was the first frequent contact with their examples, including all developers are familiar list (List), modern developers should be familiar with the Option / Maybe / Optional and further Try / Either / Result, as well as concurrent application developers Promise and so familiar. One day when I suddenly saw a piece of text mentioned that these examples is the Monad, when combined with the use of my own experience, suddenly able to understand the reason behind its definitions and problems to be solved. Perhaps this is the evolution of an ordinary developer receiving the programming process it means that from experience, summed up the law and to correspond to the definition.

I do not really understand how the definitions and abstract examples to talk Monad understand what it is, what is the use. So follow my own path Eureka, I intend to depart from its several classic examples, hoping to help you think about the general idea behind these abstract nouns and. Here I will mention Try, Promise and List, not including functional fans love the IO Monad, because the latter is very counterintuitive world other than purely functional.

Try

The first talk about the Try, which is given to concurrent programming does not yet have become an essential skill, Promise not everyone will encounter, and List developers too familiar, from another perspective might be a bit counter-intuitive .

Try to solve the problem and the traditional try-catch block is similar to the control, that is, error and exception handling. Let’s look at the traditional try-catch block write control code gives an intuitive feel.

try {
      ... // some initializations
      ... // some operations that may cause Exception
} catch (XxxException e) {
    ... // ideally we do recovery
    ... // but most of time we log and rethrow
    ... // or swallow it
} finally {
    ... // some cleanups that must be done
}

This structure looks pretty good at the time and when not nested within a try contains only a few statements, but also because we know very well what we are doing. But the prerequisite implies two questions. First, because the sake try to open a new scope, we will often write a lot of try block, and large try block without hesitation make us forget that in the end try inside the statement which what happens abnormal that even if an exception is thrown, we only know that an exception occurs, do not know who triggered because of what reason. If we split into several small segments of the try block, then we will soon be full screen indentation and due to the definition of the new scope of use value outside the try after try, and do require additional null check interference was unable to read the actual business code. Second, we sometimes nested way to deal with the specific needs and catch statements recovery might throw an exception, but this indentation as the back to speak at Promise in callback hell as fast will make you lose level of sensitivity. Practical experience indicates that as long as the two try-catch can allow developers to take over a new piece of code to the code Yun Cai.

So Try Monad is how to solve this issue? We look at a typical Try codes

val readFromFile = Try { /* IO */ } // possible IOException
val parseTheContent = readFromFile.flatMap(parse _) // possible ParseException

val tolerantParseException = parseTheContent.recoverWith {
  case _ : ParseException => /* try to fix and retry */
}

tolerantParseException.map(...)/* ... */

Code begins by Try {…} Try Monad configuration example, which corresponds to the Haskell Monad return function, i.e., a type of the upgraded Monad. We look directly at the function did

object Try {
  /** Constructs a `Try` using the by-name parameter.  This
   * method will ensure any non-fatal exception is caught and a
   * `Failure` object is returned.
   */
  def apply[T](r: => T): Try[T] =
    try Success(r) catch {
      case NonFatal(e) => Failure(e)
    }

}

NonFatal we ignore this problem, meaning that the code is to perform a operation might throw an exception if the operation is successful, returns its return value, if an exception is thrown, the exception is logged. There are two subclasses Try

final case class Success[+T](value: T) extends Try[T] { ... }
final case class Failure[+T](exception: Throwable) extends Try[T] { ... }

In both cases respectively. For subsequent code map and forEach such normal logic processing code, if Try a Failure, it will always return to its own, it is continuing to pass along the reason that is the first error. Or until a call to recover recoverWith, for these two methods, on the contrary Success will never return to its own, but Failure can be passed in the corresponding partial function, matching the specific type of exception and attempt recovery.

Therefore, the logic of the above code is read from the file and parse the data, if we try to resolve the anomaly recovery, followed by a series of operations. If you read the beginning of the abnormal, until we finally get a IOException, which may be recovered or swallowed up, or directly as a return value to return to the upper layer processing later.

In fact, we can use the try-catch block to implement the logic control code, but we find that lost in the jump logic retracted, scope and control flow; used Try Monad, we can meet linear intuitive approach to encode logic. This is also an idea of ​​functional programming, that is as far as possible all types of cases are included in the system to provide the most simple control flow (only if-else and match-case under the most extreme cases) to ensure that the program logic is down down, without doing a strange jump.

Well, this got to do with it Monad (laughs). Try-catch mentioned two problems, one is now due to the large scope try block has been Try {…} is a function of a so-called return got Try Monad package which we practice is one of the value and exception, but it is the parent Monad type class Functor have requirements. For the second question, nested try block, it only highlights the Monad solve most powerful place, which is the so-called Haskell bind function, I prefer to call flatMap function follows the list in Scala.

Try In the example, the value of the operation we may introduce a new action (e.g., the parse above) may be abnormal, unlike when we map a type from Try [T] to Try [U], parse produce is Try [Try [U]], so that the process of unpacking a later process which, we have two solutions manually nested packaging, once the series of operation increases, we will need to remember the human Solutions pack and unpack the number of layers mechanical action, although we are just interested in the final value. Even more unpleasant, we do is parse knowing the value taken out from the front of the package, corresponding to produce a result Try Monad we need, we do not need to present it in front of the reload packaging. This is flatMap meaning of existence, fitted to the front of the package to get rid of this action. No matter how many times we make an exception may occur in series, the end result is the type Try [T]. It can be said, is different from the essence of flatMap Functor and Applicative Functor is a function of the Monad.

Promise

In fact, I intend to use Java to do the CompletableFuture example of the latter to blend together and Future Promise of responsibility, maybe a little unexpected good understanding (actually inside Scala’s Promise is to achieve simultaneous mixing and Future Promise of).

When open question and I thought Promise Try represent different instances of Monad, but in fact in error recovery and processing, and multiple sub-types of the above are also a lot of similar extent. So for Try Promise and the like are calculated to represent asynchronous linear processing success or failure to tackle the problem, and the corresponding callback hell on passing. Focus here to talk about the very nature but is particularly important in the Promise Monad in Try Monad another characteristic:

By using the map / flatMap concatenation operation, to ensure that calculations are executed sequentially.

We look at the following piece of code

CompletableFuture<...> asyncOp1 = ...;
asyncOp1.thenCompose(res -> /* another async op */)
        .thenApply(res -> /* sync op */)

Async version blows it brings problems due to asynchronous Java Executor framework introduced after the first asynchronous operation code asyncOp1 pick up an asynchronous operation, after the latter received a synchronous asynchronous operation operation. This process can continue unlimited. Because Monad map / flatMap natural order of computing features that get operands can do the next action, we can ensure that these actions are in accordance with the asynchronous scheduled execution of the order. Actually, this is callback want to solve the problem, but in the development of concurrent programs that can help reasoning code. About Concurrent program development and how to select how synchronous and asynchronous operation of the order of questions, and that is another interesting theme.

List

The above two examples have a common characteristic, that indicate the success or failure of computing. But this is the Monad but in fact is not necessary.

We see List is a Monad, for this we are very familiar with the class I do not do basic introduction to the contrary, from the definition of Monad’s List is to examine how to become a Monad.

For the Monad, it needs a function and return a bind function. For List, its return is x = [x], and that bind the flatMap List function.

List is a more simple example can help us to see the specific circumstances flatMap happened. For example, we do a multiplication table, the wording is imperative

for (int i = 1; i < 10; i++) {
  for (int j = i; j < 10; j++) {
    System.out.println(i + " x " + j + " = " + i * j);
  }
}

The use of flatMap List Monad function, we can write

mapM_ putStrLn
   $ do 
       x <- [1..9]
       y <- [x..9]
       return (show x ++ " + " ++ show y ++ " = " ++ show (x * y))

In Java Stream, we can get the result x * y, but in front of the x and y capture a little bit difficult (you can use forEach, but in fact has been forced to unpack forEach consumer can no longer install package).

IntStream
    .range(1, 10)
  .flatMap(x -> IntStream.range(x, 10).map(y -> x * y))
  .forEach(System.out::println)

UPDATE

After I found the way Java is a scene I did not understand the special nature of primitive data types, in fact, it is possible to achieve the same effect with Haskell, although not do syntactic sugar looks more like Expand do syntactic sugar

IntStream.range(1, 10).boxed().flatMap(x ->
        IntStream.range(x, 10).boxed().flatMap(y ->
                Arrays.stream(new String[]{ x + " * " + y + " = " + (x * y) })))
        .forEach(System.out::println);

summary

Monad usage scenarios is very broad, both in exception handling and concurrent programming in emerging Try and Promise, or with us for the long-List, as well as functional in the world to handle state changes State Monad and order additional side effects the IO Monad, in the final analysis, the core lies Monad flatMap additional functions and actions in the apparatus depacketizer definable (in Haskell, the underlying platform any additional advantage of this operation to achieve the IO Monad side effects). Artisans from the code perspective, see more and more thinking to use Monad characteristics of high-quality code can help to understand and learn Monad practical effect. More projects this part of the code, simply can recommend Pravega and Apache Flink both extensive use of the Promise project. Recommended books terms "Java Functional Programming" and "magic Haskell". The above description in the mix, but not a lot of Monad has unique content, follow these two books to understand functional programming which is how from simple to complex, step by step to provide a new solution for a new problem, this process is very interesting .

Leave a Reply