In the final unit of this week, we'll cover some of the general theory that underlies what we have seen before. We're going to study a very general class of design patterns that come up almost everywhere in functional programming and also in reactive programming. The theoretical foundation of this class of design patterns, is embodied in the concept of a monad. As we've seen, data structures with map and flatmap, are quite common. And in fact, there's a name that describes this class of data structure, together with some algebraic laws, that they should have. These data structures are called monads, a monad is a parametric type M with a parameter type T that has two operations, flatMap and unit. And these operations also need to satisfy some laws. So, you could can see it in Scala as trait M by M is T, is tympanometer it would have a flatMap method of the type that you see here so, takes an arbitrary type U as a parameter and a function that Maps of T to a monad of U and it gives you back the same monad applied to you and besides flatMap, there would also be the unit method, that unit method takes an element of type of T and gives you an instance of the monad of T. In the literature flatmap is more commonly called bind but in Scala we have flatmap already a established name so I will continue to use that. Here are some examples of monad, this is a monad where unit is just the single element constructor so given an x I return the list that consist of just x Similarly, set this a monad where you need to fix this fix. Option is a monad where unit is Some so, unit of x would be, I have an element and here it is and the random value generators that we've seen on the last unit, they're also a monad where unit of x is the single generator, single of x As you've seen, flatMap was available as an operation on each of these types, whereas the unit in Scala is different for each monad. Quite often it's just the name of the monad type applied to an argument, but sometimes it's different. For instance, for generator we use single, for option we use Some So we've seen monads have the flat map operation. What about map? Well in fact map can be defined for every monad as a combination of flat map and unit. So, the map applied to a monad with the function f would be flat map of First apply f to the argument x and then reinject into the m map using unit. Another way to write this expression would be to use the and then Combinator instead of the f for function composition So you could m map f is m flat map of f. And then unit. So you first apply the m function and then you apply the unit function to the result of that. Now in Scala, we do not have a unit that we can call here because every monad has a different expression that gives the unit value. Therefore, map is in Scala a primitive function that is also defined on every monad. to qualify as a monad, a type has to satisfy three laws that connect flatmap and unit. Associativity is as usual a law about placing parentheses The parenthesis would be placed on the left hand side, and here you see them placed on the right hand side here. So we can alternatively either do the flat map here first or combine the two functions in the flat map, and apply to the monad. Domain is a bit easier to express if we go from monads to monoids. Monoids is a simpler form of monads. That doesn't bind anything. So, for instance, integers are a Monoid, and they're associative because (x + y) + z is the same thing as x + (y +z). So, again, I can put the parentheses either to the left or to the right. The second law that needs to hold for a Monad is called left unit. It says that if I inject into the Monad using unit, and then flatMap with f and the result is simply the same as simply applying f(x). The last law is Right unit. It says that if I flatMap with the unit constructor, I end up with the same monad value as before. Let's check the Monad laws for example type. I pick option for that. First thing we have to do is look at flat map for option. So what flat map should do is it should take an optional value. If that optional value is so we have nothing and we keep none. If the optional value is something with a value x, we apply a given function to that value. And that will give us another optional value. Let's start to prove the left unit law. What we need to show here is that unit of x for option that was some of x, as you know. FlatMap f is the same thing as f(x). So, let's start with that expression, Some(x) flatMap f and expand what flatMap. So, flatMap is this pattern match that says well, if it's Some(x), then apply f to it. If it's None, keep on having None. Now that we can simplify obviously, because we have a Some(x) here, so it clearly matches the first pattern. And that would give us f(x) as the result. So the left unit law holds. Let's look at the right unit law now. So the right unit law says that, some optional value flat map with some which is the unit constructor is the same thing as that optional value. So we start with the left hand side, optional value flatMap sum. We expand what flat map means, so we again have this pattern match which says will match if it's some of x then we turn now, our function f is sum. So the function f here gets inserted here so we return sum of x, and if it's none we return none. Then again simplifies to just opt because we see that in each of the two branches of the pattern match we turn exactly the thing we started with. So the right unit law holds also. finally, we have to check the associate law, so here it is. We need to show that the sequence of the two flat maps with the parentheses to the left is the same thing as a flatmap of a flatmap with the parentheses to the right. So let's start with the left again. Here we have the sequence of the two flatmaps here is what it expands to. So that line is the first flatmap with the two pattern matches now on one line. And the parentheses go to this That's its expansion. So that result has to be subjected to the second flatmap, so here we immediately follow the first match with the second one which now implements the flatmap called with g instead of f before. So that's the expansion of this expression. Now what I do is I take the Second pattern matched this one here. And I move it inside the two branches of the first one. So I know that the result of the first pattern match will be the selector of the second one. All I did here was to say well let's take each branch of the first pattern match and make it a selector of the second one. So I pulled this second selector in here, and in here. That gives me this expression here and that expression now in turn we can simplify so let's look at the case None here first so if the optional value is None Then we have the match None match case some y => g of y case None => none. So obviously it would be the second pair on match that applies. And the whole expression simplifies to this one that you see here. So the second case is just if get a None, we keep a None. Let's turn to the first case. So in the first case if we say well if we got a some(x) then we match f(x) in turn. Again if we get a some(y) we give a g(y) and we keep a none. So what that is, if we look at things in reverse it's just f(x) flatMap g. Because if we expand flatMap g then that expansion in turn gives us exactly that pattern match here. And if we look at that expression in turn and we see there's just another instance of a flatMap. This time the flatMap is with this function here. So we say well it's the function that says given an x it will return this expression here. So we get opt flatMap x arrow f of x flatMap g. That's exactly the right hand side of our original equation we wanted to prove. So, option is a monad because those three laws hold as we have just shown. You might ask well, why should I care about the monad laws? What significance do they have for programming practice? Well, one answer to that is that they give a justification for certain refactorings of for expressions that are quite intuitive. The associative law says essentially that one can inline nested for expression. So if I have a full expression like that where the first generator is in turn a full expression, what I can do is I can essentially inline the two Generate this here in one large four expression and the result would always be the same provided that the type in question satisfies the associativity law. The right unit law also has Bears a significance for for-expressions. It essentially says that the trivial for-expresson here where I generate x and immediately return it is the same as the original value that you see here. For the left unit, though, I haven't found an analog like that for for-expressions. So, it seems that as what concerns behavior for for-expressions only associativity and right unit is important. So here's another type that might or might not be a Monad. We'll find out and that type will be important in the later parts of this course. The type is named Try and it resembles option except that instead of sum and none, there are two cases which are named success and failure. The success case returns a value just like sum does. But the case return something an exception. So the idea is that Try with be used in cases where we want to propagate exceptions, not at the call stack but say between different threads of different processes, or even between different computers. So in a sense we want to bottle up an exceptions In a value that we can then freely pass around. Here's a definition of the try class, it's an abstract class try with a T parameter just like option. The success case extends Try and gives you simply a value of type T The second case, Failure, contains an Exception and extends Try of Nothing. As you've seen in the functional programming course, nothing is the bottom type in nothing doesn't have any value and it typically refers to something that is either a missing value in the Exception Or the computation that does not return normally because maybe the computation throws an exception or it loops infinitely. So a typical way to create tri-values is Using try of expression so you can wrap an arbitrary expression in try and that is achieved by making try an object in the standard library that has an apply method. So you've seen that anything that has an apply method can be applied just like a function. The same holds for objects such as try. So what is the definition of the supply method? Well, it would take an expression, a computation, and return a Try of the paper of that computation. And what it would do is it would use a Java Try, so a Try that you know from the JVM That's written in lowercase try. So we try to compute the value of expression and rapid and success. If the computation here throws an exception, that will be caught here in the block and the exception will then be wrapped in a failure value. And returned as a result. That happens for any exception that is non fatal. Non fatal is fairly technical thing. Essentially, an exception is fatal if it doesn't make sense to export this beyond a single thread. There are a couple of exceptions that are. But the vast majority of all exceptions. Both runtime exceptions and normal exceptions. Exceptions are non-fatal. What's important here is that the expression is parsed as a by name parameter. Because otherwise of course we would already have a value here. So there wouldn't be a computation that could throw an exception. So that's why you have to type arrow key indicating call by name parameters. Just like with option try value computation can be composed in four expressions. So, for instance, you could write for x taken from some computation computeX, y taken from some computation computeY. Yield, the result f applied to x and y. Wherever some function that takes an x and a y value. So what that means is that if compute x and compute y both succeed, so they both give you results success (x) and success (y) respectively, that will return a success value with the value f of x,y. But if either computation fails with an exception, this will return failure with the first exception that got wrong. So to support this kind of notation all we need to do is define map and flatMap in the right way on the tripad. Here the definitions of flatMap and map on the Try type. Let's look at flatMap first. So flatMap takes a function from the main T gives us a Try of [U]. And what it would do is it would say, well if we start out with a success so we have a value x. Then let's apply f to x, that would give us the result value. But on the other hand if the function f itself Throws an exception which is not fatal then let's package this up in a Failure value because there's a principle that you will never leak non fatal exceptions from a tri computation. On the other hand, if we started out with already a failure and an exception then that gets propagated into the result and returned here. What about map? So map just takes a simple function from T to U, and we have to wrap it up in a Try. The way this is done is again pattern match on success and failure. If we have a success x, then let's apply f to x and submit it to the try constructor. So that, again, would, if f throws an exception, give us a failure. If f returns a value, then we would wrap that in a success. And, as before, failures get propagated in the result. So if we look at the relationship between flatMap and map and that's what we have here. I try value of map with the function f is the same thing as a flatMap where the function f gets supplied to x, and then the result gets trap in a try because that’s how map was defined. And if I rewrite that expression here I get t flatMap f and then try. So t map f is the same thing as t flatMap f and then try. So having map and flatMap defined like this and try values suggests that try might be a where the unit is the try constructed itself. Is it? Possible answers would be yes, it is, or it isn't. And in that case, I would also like to know why it isn't. So it couldn't, it might not be a monad because the associate law fails, or the left unit, or the right unit law fails. Or maybe two monad laws fail. What do you think Well if you check the laws, then we find out that in fact the left unit law fails. Lets see why. So what's the left unit law for tries? It says that the unit, so that would be try, apply to an expression flat map of function f would have to be the same as f applied directly to the expression on the left. But, it isn't we have a non-equality here and why is that? Well, the left hand side here as we've seen will never raise a non-fatal exception neither try nor flat my board whereas of course. The right hand side will raise any exception that's thrown by the f or expression. So that means that the left unit law can not possibly hold for a good implementation of Try. And otherwise put, that Try, in a sense, trades one monad law for another law Which in this context is more useful. Let other law, I call it the bullet proof principle would be that an expression composed from 'Try', 'map, and 'flatMap' will never throw a non-fatal exception. To conclude, we've seen that for-expressions are useful not only for collections. Many other types also define map, flatMap, and withFilter and that enables them for for-expressions. For-expressions can be written over these types, then. Examples we've seen were Generator Option and Try. We've seen that many of the types that have a flatMap and map functions are in fact monads. That means that we can also give a unit and constructor and we can verify that they satisfy the monad laws. You might ask, what about filter, we haven't seen filter so far. Well, it turns out that if these monads define also with filter and satisfies certain additional laws they are called monads with zero, which is somewhat which are category than monads. The three monad laws that you have seen get useful, and the design of library API's. That is always for every law you also have to know when to break it. We've seen that the laws do apply to Option and the values for that, but they don't all apply to Try, the left unit law fails. On the other hand we've also seen that the left unit law itself doesn't really have a good explanation in terms of for-expressions. So that would mean that while Try is not a monad, it is still a type that can be used in a perfectly safe and reasonable way as the carrier type of a for-expression.