The vertical form, full video shorts collections, presentation going around the basic concepts surrounding functors, monoids and monads. They are discussed in Haskell and Kotlin domains and the idea is to give an empirical and instinct feeling about what they are, so that we can process better our thoughts with higher level concepts to find solutions for our every day programming language challenges.
---
Documentation:
- Scribd: https://www.scribd.com/presentation/779087903/Monads-Are-No-Nomads
- GitHub - Kotlin Test Drives : https://github.com/jesperancinha/jeorg-kotlin-test-drives
- GitHub - Haskell Test Drives: ttps://github.com/jesperancinha/haskell-test-drives
---
Sources:
- https://www.dcc.fc.up.pt/~pbv/aulas/tapf/handouts/monads.html
- https://userpages.cs.umbc.edu/artola/studyaids/AbstractAlgebraPrimer.pdf
---
As a short disclaimer, I'd like to mention that I'm not associated or affiliated with any of the brands eventually shown, displayed, or mentioned in this video.
---
All my work and personal interests are also discoverable on other different sites:
- My Website - https://joaofilipesabinoesperancinha.nl/
- Reddit - https://www.reddit.com/user/jesperancinha
- Credly - https://www.credly.com/users/joao-esperancinha/badges
- Pinterest - https://nl.pinterest.com/jesperancinha/
- Instagram - https://www.instagram.com/joaofisaes/
- Facebook - https://www.facebook.com/joaofisaes/
- Spotify - https://open.spotify.com/user/jlnozkcomrxgsaip7yvffpqqm
- Medium - https://medium.com/@jofisaes
- Daily Motion - https://www.dailymotion.com/jofisaes
- Tumblr - https://www.tumblr.com/blog/jofisaes
---
If you have any questions about this video please put a comment in the comment section below and I will be more than happy to help you or discuss any related topic you'd like to discuss.
If you want to discover more about my open-source work please visit me on GitHub at:
- GitHub - https://github.com/jesperancinha
--- YouTube
A full long form video, with a wrapping powerpoint presentation is available on Youtube over here: https://youtu.be/ShGAN0dguUg
-
---
Documentation:
- Scribd: https://www.scribd.com/presentation/779087903/Monads-Are-No-Nomads
- GitHub - Kotlin Test Drives : https://github.com/jesperancinha/jeorg-kotlin-test-drives
- GitHub - Haskell Test Drives: ttps://github.com/jesperancinha/haskell-test-drives
---
Sources:
- https://www.dcc.fc.up.pt/~pbv/aulas/tapf/handouts/monads.html
- https://userpages.cs.umbc.edu/artola/studyaids/AbstractAlgebraPrimer.pdf
---
As a short disclaimer, I'd like to mention that I'm not associated or affiliated with any of the brands eventually shown, displayed, or mentioned in this video.
---
All my work and personal interests are also discoverable on other different sites:
- My Website - https://joaofilipesabinoesperancinha.nl/
- Reddit - https://www.reddit.com/user/jesperancinha
- Credly - https://www.credly.com/users/joao-esperancinha/badges
- Pinterest - https://nl.pinterest.com/jesperancinha/
- Instagram - https://www.instagram.com/joaofisaes/
- Facebook - https://www.facebook.com/joaofisaes/
- Spotify - https://open.spotify.com/user/jlnozkcomrxgsaip7yvffpqqm
- Medium - https://medium.com/@jofisaes
- Daily Motion - https://www.dailymotion.com/jofisaes
- Tumblr - https://www.tumblr.com/blog/jofisaes
---
If you have any questions about this video please put a comment in the comment section below and I will be more than happy to help you or discuss any related topic you'd like to discuss.
If you want to discover more about my open-source work please visit me on GitHub at:
- GitHub - https://github.com/jesperancinha
--- YouTube
A full long form video, with a wrapping powerpoint presentation is available on Youtube over here: https://youtu.be/ShGAN0dguUg
-
Category
🤖
TechTranscript
00:00:00That's why we call it RightNodeRightLeafValue.
00:00:04Finally, we build a tree with this instruction over here.
00:00:07And this tree then is composed by a node and then by a leaf,
00:00:12which then we put in as this LeftNodeLeftValue.
00:00:16Then we create another node, which will have now two leaves.
00:00:20This one, which we fill in with this variable over here.
00:00:23And then finally, on the right, we fill in with this RightNodeRightLeafValue,
00:00:27which we have put right over here from this readline input.
00:00:31Finally, we return the tree.
00:00:33On the next declaration, we define our main function.
00:00:37And our main function, which is also an IO functor,
00:00:41is our entry point of our application.
00:00:43And the first thing we do is call the RightBuildTree
00:00:45and associate the return value to tree.
00:00:48So this means that we'll go through all the different inputs,
00:00:51get our new customized tree,
00:00:53and then continue with the execution of the program.
00:00:55We print the tree to the output.
00:00:57And then finally, we add a number to all the leaves associated to the tree.
00:01:00And to do that, we'll get the number again via a readline.
00:01:04When we get this number in the num variable,
00:01:06we then are able to do an fmap
00:01:09by adding this num to all the elements of the leaves of the tree.
00:01:13And this is accomplished by using this half map.
00:01:17This fmap will call precisely what we have defined over here.
00:01:21And this means that it will trigger a cascade of additions
00:01:25throughout all the leaves inside our binary tree.
00:01:29And that means that at the end, we will get an updated tree
00:01:32with the number that we've decided to add to all the leaves to it.
00:01:36And to see this working, let's now compile our program
00:01:39and run it from the command line.
00:01:41So now we can just compile our bonus example.
00:01:43And to do that, we just need to run ghc bonus map tree.hs.
00:01:51And now we should have our natively compiled auto-executable file,
00:01:55which we can then run like this.
00:01:58And now we only need to enter the values for our tree.
00:02:00So for the left node leaf, we just say, for example, a 4.
00:02:04For the right node left leaf, we can put a 6.
00:02:08And then for the right node right leaf, let's say a 10.
00:02:13And now let's add a number to all the elements of the tree.
00:02:15Let's say 2.
00:02:19What we get is a tree that has a left node
00:02:23with a leaf with number 6.
00:02:25This number 6 was achieved because, if you remember,
00:02:28the first number that we have set for our left leaf was number 4.
00:02:33And then we've decided to add a 2 to all the elements of the tree.
00:02:37So that means now we have a 6 on the left side.
00:02:40The same thing for the node on the right and its leaf on the left side.
00:02:45We get an 8.
00:02:46And the reason we get an 8 is because the second value we added was a 6.
00:02:50And now if we add 6, a 2, then we get an 8.
00:02:53Finally, the same thing, leaf 12, we have set a 10.
00:02:56And then we've decided to add 2 to all the leaves.
00:02:58And that means here we get a 12.
00:03:01But let's make the last test.
00:03:02And that is, again, to create a new tree.
00:03:06So next tree.
00:03:08And let's just say that this is going to be resulting from an fmap of the last tree
00:03:18where we are going to apply a 5 to all the elements of that tree.
00:03:23So this is going to be the updated tree that we will map to the new one.
00:03:29And then we will print the resulting tree.
00:03:32Next tree.
00:03:37If we now compile this program, we will see exactly what I've just described.
00:03:42So if we say ghc bonus map3.hs, it should now compile.
00:03:50We've got the new command.
00:03:52And then we just run it like this.
00:03:55And now let's just say, for the sake of comparing the two examples,
00:04:00let's use exactly the same values.
00:04:02It was a 4, here we had a 6, and here we had 10.
00:04:06And now let's say we want to add 2 to that tree.
00:04:08We've got the same result as before, 6, 8, and 12.
00:04:14And look what happens now in the next nodes.
00:04:16The next tree has been mapped with this function that adds a 5
00:04:20to whatever element they have inside, in this case an integer.
00:04:25And in that case, 6 plus 5 is 11, 8 plus 5 is 13, and 12 plus 5 is 17.
00:04:31So this example, which is a bit more elaborated, showed us a few things in action.
00:04:34The IO functor, it showed us also the actual way to declare a functor.
00:04:40It showed us how IO works in the return values of functions.
00:04:44And it showed us how to get values from the command line using readline
00:04:49and how that works with IO.
00:04:51This finishes our examples about functors in Haskell and Kotlin.
00:04:57The next concept for our study is monoids.
00:05:01The next concept for our study is monoids.
00:05:04What are they? How are they used?
00:05:06How do they differ from functors?
00:05:08And how does that lead to monads?
00:05:12To see what monoids are and how they work,
00:05:15we should go back now to our Kotlin test drives project.
00:05:18And there we can go to this folder over here.
00:05:23Monads are no nomads.
00:05:26And inside of it, if we go to the test folder,
00:05:30we should be able to see a test that is specific for monoids.
00:05:38And one of the important things about monoids is that they have three properties
00:05:43that we need to respect in order to call something a monoid.
00:05:47And for that, we can go through notes, particularly by universities.
00:05:52For example, we can look at the notes for the Maryland University.
00:05:56And there we can find this description of what a monoid should be.
00:06:01And it says there that a monoid M is a set M with a binary operation star
00:06:07that satisfies the following properties.
00:06:09There are three properties.
00:06:12One is closure, the other one is associativity,
00:06:14and the other one is identity.
00:06:16The closure only means in broad terms
00:06:20that if we create a result from a binary operation,
00:06:25the result of the operation will remain in the same domain.
00:06:30And that means that we get an object that should be of the same type
00:06:34of the elements of the operation.
00:06:38Then we have the associativity operation.
00:06:41This should be fairly familiar.
00:06:43And if not, the idea is that we can exchange the position
00:06:46of the different elements of the operation
00:06:48and obtain the same result.
00:06:52We can try to easily define what identity means.
00:06:55But in this case, there are three ideas behind this identity.
00:07:01One is that if we perform an operation with an element
00:07:06against the target element that we have,
00:07:10the order shouldn't matter and we should get the same result.
00:07:13But also the result of that operation should be equal to the element itself.
00:07:18So that's why we have here E star A,
00:07:22A star E, and just A.
00:07:25And all of them are equal to each other.
00:07:29But in Kotlin, we can also check this and see
00:07:33if one of the types that we want to test is actually a monoid or not.
00:07:39A list is in Kotlin a monoid.
00:07:43And to check this, I have created three tests
00:07:45so that we can see an example running of why a list should be a monoid.
00:07:51In the first example, I call the test
00:07:53ShouldTestMonoidList to have an identity.
00:07:56So this is one of the properties that we have just seen in the list.
00:08:00And in this example, we find that an empty list
00:08:06could be an indication that a list is a monoid.
00:08:10What this means is that if we try to add an empty list
00:08:15to a tree collection, which is this list over here,
00:08:20it is created with a range of numbers from 1 to 10.
00:08:24And those are mapped to instances of a tree type
00:08:29where each element contains 10 leaves.
00:08:34And so if we go back to our example,
00:08:38we see that when we add an empty list to a tree collection,
00:08:42the result should be the same as if we would add
00:08:46an empty list to the tree collection.
00:08:50And the result should also be a tree collection.
00:08:53And that is an example that I could also add here.
00:08:56So for example, if I pick up this part over here
00:09:01and then I do it like this, and then I add,
00:09:06and then I say that this should be the tree collection,
00:09:12this example should run without any faults.
00:09:18And that's exactly the result that we get here now.
00:09:22And we can see that all of these assertions ran correctly.
00:09:28And this proves the identity property of the list.
00:09:32So we only need to test now two more properties.
00:09:36And the second property that we can test is the closure property,
00:09:40which is a bit more complicated,
00:09:43because when we are working with Kotlin,
00:09:45we are also working with Java types under the hood.
00:09:48So that means that we need to be careful
00:09:50with which types we are using and comparing our collections to.
00:09:54So the first line of code means that I am creating
00:10:00a pre-tree collection 1, which is a list of two different trees.
00:10:04And the trees have a list of leaves.
00:10:07It doesn't matter which ones.
00:10:09What's important here is that we create a list of trees.
00:10:12And then because of the different Java types between Kotlin and Java,
00:10:16I need to call that toList to make sure that I get the exact list type
00:10:20that I am using with the tree collection that I've just shown.
00:10:24And I do a print line there so that we can clear that up
00:10:28and see why I have done this.
00:10:32But the whole point is that I have created now a list of two trees
00:10:36that are different than the trees in the tree collection.
00:10:40But if I add them together with this plus,
00:10:45which is our binary operation,
00:10:49then that means that the result should only have types of trees.
00:10:53And this would satisfy the closure operation.
00:10:57So if I run this, the same thing should happen.
00:11:00The test should run correctly.
00:11:03And we see that it has run correctly.
00:11:07And we can also find here under
00:11:11the reason why I did that toList,
00:11:14because in the first case,
00:11:17when I made it pre-treeCollection1,
00:11:20the type is Arrays$ArrayList,
00:11:23which is a different type than just ArrayList from java.util.
00:11:28But the whole point is that our binary operation is still the same.
00:11:32It's a plus.
00:11:33It has been applied to lists.
00:11:35And a list in this case still complies
00:11:38with the idea that it is a monoid,
00:11:41because we were able to perform an operation
00:11:45with two different elements that result in an element of the same domain.
00:11:48But we still have another property that we want to test.
00:11:51And that property is the property of associativity.
00:11:54And in this last example,
00:11:57we see that we have a test here
00:12:01that is called shouldTestMonoidList
00:12:04And here I have created three different collections.
00:12:08And these three different collections
00:12:11contain two different trees.
00:12:14And the only thing that we're going to do
00:12:17is to sum all three of them in different ways.
00:12:20So in this assertion right over here,
00:12:24we first sum the treeCollectionA
00:12:27with treeCollectionB.
00:12:30And then when we have the result of that,
00:12:33and again, it is the same binary operation.
00:12:37And then we try to assert if that result
00:12:40is the same as adding B and C
00:12:43and then adding that to collection A.
00:12:46And it should not be a surprise now
00:12:49if we run this test,
00:12:53that the assertions run correctly
00:12:56and that there is no fault reported.
00:12:59Because essentially what we have proven here
00:13:02is the property of associativity.
00:13:05Lists, in this case,
00:13:09because we can apply a binary operation
00:13:12and specifically in Kotlin,
00:13:15in this case, they can also be considered monoids
00:13:18because they satisfy all the three different properties
00:13:21that we have seen in the notes
00:13:25for the University of Maryland in this case,
00:13:28which we can find these notes in all kinds of universities.
00:13:31This is an example of a monoid.
00:13:35And that is a list.
00:13:38But let's check other examples like either,
00:13:41like optional, and see how that works
00:13:44and if those also comply with the idea of a monoid.
00:13:47Lists are an example of monoids.
00:13:51But what can we say about option, for example?
00:13:54We have seen that before, that it works really well as a functor
00:13:57and it matches all the characteristics of a functor.
00:14:00But does it match the characteristics of a monoid?
00:14:03Let's have a look.
00:14:06When we look at this example right over here,
00:14:10we can see that I have tested the option
00:14:13against the three different properties that we have mentioned before.
00:14:16So let's recap.
00:14:19It was identity, then we had the associativity option,
00:14:22and then we also had the closure option.
00:14:26As we look now at this test,
00:14:29we may be led to believe that the option is a monoid.
00:14:32This type, maybe it's a monoid.
00:14:36Let's have a look more closely into the test.
00:14:39So right over here, I am testing
00:14:42that the identity property stands.
00:14:45Then I check here
00:14:48if the closure property stands,
00:14:52and then right over here if the associativity property stands.
00:14:55And as we look at all three,
00:14:58it seems like everything is okay.
00:15:01But there is a difference.
00:15:04I have modified the option to be able to comply
00:15:07with all of the properties of a monoid.
00:15:11However, the way I did that
00:15:14is simply creating an extension function
00:15:17for the option tree,
00:15:20and option tree now is extended to have a plus operation.
00:15:23And the plus operation in Kotlin
00:15:26is called the operator modifier,
00:15:30and that means that we can use plus freely
00:15:33for the different operations we want to execute,
00:15:36and then it will work as a binary operator.
00:15:39So that means you will have option as an operand A
00:15:42and as an operand B, and the result will be C,
00:15:46which will also be an option of tree.
00:15:49But now if I remove this and I comment it out,
00:15:52we'll see that the code does not compile anymore
00:15:55because that's kind of also the magic of a monoid,
00:15:58is that it is entirely dependent of one binary operator
00:16:01that for the most part will comply
00:16:05with the three different properties
00:16:08that a monoid should have.
00:16:11So what this means and what this tells us
00:16:14is that although an option can be a functor,
00:16:17it doesn't necessarily mean that it is a monoid.
00:16:21Does it mean that there will be a monoid
00:16:24or does it mean that there will be a monad?
00:16:27Well, we'll have to wait until the rest of this video
00:16:30to be able to assess that.
00:16:33But for now, keep this in mind.
00:16:36An option is not a monoid
00:16:40because it doesn't comply with any of the properties
00:16:43that a monoid should have.
00:16:46It is a functor, and because it is a functor,
00:16:49we can make interesting things with it
00:16:53and make it a monoid-like type.
00:16:56If I reinstate
00:16:59this extension function once again,
00:17:02the code will compile again.
00:17:05And this is interesting because now
00:17:09if we look at the first test,
00:17:12we see that the testing
00:17:15that the custom monoid option
00:17:18has an identity will work.
00:17:21And the reason for that is that I can create
00:17:25simply a tree with no leaves
00:17:28that I will assign to be my identity value.
00:17:31And that identity value can be added
00:17:34to another tree that does have one leaf.
00:17:37And by adding it to it, it will result
00:17:41in a tree that has the same leaf.
00:17:44And otherwise, it will also return
00:17:47the same tree with that leaf.
00:17:50As a result, it will also be
00:17:53equal to the same tree
00:17:56with that leaf.
00:18:00If we run this test,
00:18:03it is now obvious with what I said
00:18:06that it will run without any faults.
00:18:09And that's exactly what we see right now.
00:18:12The test ran correctly in these two assertions.
00:18:16The first assertion with the combination
00:18:19value and the second assertion
00:18:22with our value being checked against
00:18:25the sum of our value with the
00:18:28identity value, which will be itself.
00:18:31And that's why this test now works.
00:18:35One thing though is that we consider tree
00:18:38in all of these cases to be the same,
00:18:41our tree with leaf, although technically
00:18:44behind it the tree object itself
00:18:47because when we are
00:18:50making an addition with this operator,
00:18:54we are effectively creating a new tree
00:18:57with this copy.
00:19:00That's essentially what's behind the extension function.
00:19:03That gives the appearance that the sum with our
00:19:06identity object doesn't change the actual tree.
00:19:10It does change it technically, but that's not
00:19:13what we see in the actual values in the code.
00:19:16So this tests the identity property of this
00:19:19custom option that we have created.
00:19:22In the second case, we will check for closure.
00:19:25And closure is very simple to test.
00:19:29It is quite easy to just see from our extension function
00:19:32that the result is actually an option tree again.
00:19:35And this case is a sum.
00:19:38But before I continue to explain what closure means
00:19:41for our type option and how we are changing option
00:19:44to behave like a monoid, we need to pause
00:19:48for a moment and see what we have done so far
00:19:51and if we have made the right decisions
00:19:54in that respect.
00:19:57Option is inherently not a monoid,
00:20:00but we are making changes for it to have
00:20:04a monoid-like behavior.
00:20:07But in the process, we need to be careful about a few things.
00:20:10Is it possible to change it to actually be a monoid?
00:20:13There might be a way.
00:20:16And in order to do that, we have to go back to what we did.
00:20:20And for that, I will compare this code
00:20:23that I have changed already to achieve that
00:20:26with the old code that we had before
00:20:29and that I presented up until this point
00:20:32in these series of videos.
00:20:36So let's now compare it with the correct revision.
00:20:39And this is the correct revision.
00:20:42And if we go back to the test that was checking
00:20:45for our option object to have an entity,
00:20:48we will see one important thing.
00:20:51In the old code,
00:20:55I was creating an empty option
00:20:58with a tree with no leaves on it.
00:21:01And that is this one.
00:21:04But this object has a very important flaw
00:21:07in the set of characteristics of an identity.
00:21:11It cannot be an identity because this one is an object.
00:21:14And what we need for an identity is a literal.
00:21:18What is the difference?
00:21:21In this case, we have a reference and we have a value.
00:21:24The reference is this one over here,
00:21:27option tree empty.
00:21:30And this whole thing here is the value
00:21:34that is attributed to that reference.
00:21:37And on this side, we don't have a local object
00:21:40that is an entity.
00:21:43In this case, we are calling an empty option tree,
00:21:46just like over here.
00:21:49And we are testing for the identity.
00:21:53Now this works.
00:21:56But what is the fundamental difference here?
00:21:59If we go all the way down in the code
00:22:02and we check the old implementation,
00:22:05what we used to have before,
00:22:08we have a tree of the second operand
00:22:12with the first operand.
00:22:15That is, the second tree with the first tree.
00:22:18It looks good, but it fails to acknowledge
00:22:21the fact that one of the operands may be the identity.
00:22:24And in that case, we don't need to perform
00:22:28any special operation.
00:22:31But this is always doing that operation
00:22:34because those options that we were referring to as entities,
00:22:37that odd concept, it should actually be something
00:22:40that would say to us immediately that it is an identity.
00:22:43Well that identity, which is something that I have created
00:22:47over here, and that is a function.
00:22:50And that function is calling our identity.
00:22:53And our identity in this case is none.
00:22:56This none is interesting because this none
00:22:59is simply an object
00:23:03that is also an option of nothing.
00:23:06While being an option as well.
00:23:09So that means that this none
00:23:12is really our identity because this none
00:23:15is only a literal.
00:23:18It's a value, we can reference it,
00:23:22but it's still just a value.
00:23:25And in that case, every time we use none,
00:23:28it is the same none all the time.
00:23:31And so the operation that we have specified,
00:23:34is a bit different now.
00:23:38It starts off with a when.
00:23:41And this when is going to check if this is none,
00:23:44then we will return anyways the second operand.
00:23:47Because even if the second operand is none,
00:23:50we have to return one of the nones anyways.
00:23:54But in this case, we return the second operand.
00:23:57In the second case, the second operand
00:24:00is the one that may be none.
00:24:03And otherwise, we just make that operation
00:24:06that will sum up the leaves of our trees
00:24:09in our option object.
00:24:13Which means that we return a new object.
00:24:16But that is understandable,
00:24:19and that has nothing to do with the identity,
00:24:22it's just the result of the binary operation
00:24:25that we are running.
00:24:29This identity was the only thing that stood in the way
00:24:32of saying I have an object with a monoid-like behavior,
00:24:35and saying I have a monoid.
00:24:38Because now we do have an option
00:24:41that has been changed in such a way
00:24:45that it has an identity that is being used
00:24:48in this binary operation,
00:24:51that satisfy the idea that A plus identity
00:24:54equals to identity plus A equals A.
00:24:57And so this is no longer a monoid,
00:25:00and so this is no longer a monoid-like object.
00:25:04We can say that this is a monoid,
00:25:07that we have changed option to be a monoid.
00:25:10Much in the way of a list.
00:25:13Because before, we have mentioned that a list was a monoid,
00:25:16because it had an identity,
00:25:20and that identity was an empty list.
00:25:23But not just any empty list.
00:25:26Our empty list in this case is also a literal.
00:25:29Or maybe this is one of those literals
00:25:32that are not well known in the Kotlin library.
00:25:35If we go to empty list,
00:25:39and we check what it has,
00:25:42it has this actual empty list type.
00:25:45It returns an empty list type,
00:25:48and if we check what it is,
00:25:51this empty list type is an object.
00:25:55An object of what?
00:25:58And so we can use this very well in operations,
00:26:01but List has already implemented its own binary operations,
00:26:04which is what we use with that plus.
00:26:07And that plus, that binary operation,
00:26:11is of course something created with the operator modifier in Kotlin.
00:26:14So now let's go back to our example,
00:26:17and finish off what we were saying.
00:26:20But now we can say that option now,
00:26:23after this modification, is actually a monoid.
00:26:26We need to revise two more things.
00:26:30One is what I was already talking about in the last video.
00:26:33And that is,
00:26:36the closure property.
00:26:39And the closure property simply just says,
00:26:42as we have seen with the list example,
00:26:46that if we sum two of these elements,
00:26:49the resulting element will be of the same type.
00:26:52So that means in an operation where a plus b equals c,
00:26:55are of the same type.
00:26:58Which is kind of what I test here.
00:27:01Essentially I'm testing that option tree color black,
00:27:05the first tree,
00:27:08should be of type SumTree.
00:27:11When added to an option tree color orange,
00:27:14which should be of SumTypeTree,
00:27:17means that the result has to be a SumTypeTree.
00:27:21That means that
00:27:24a plus b equals c,
00:27:27which should be of type SumTree.
00:27:30which should be of type SumTree.
00:27:34which should be of type SumTree.
00:27:37And the following test checks for associativity.
00:27:40And associativity in this case,
00:27:43means exactly what we saw in lists.
00:27:46So that means that a plus parenthesis,
00:27:50b plus c equals a plus b plus c.
00:27:53Just as we see over here.
00:27:56So this means that adding the option tree color pink,
00:27:59to the sum of the option tree color black,
00:28:02with the option tree color orange,
00:28:05should get us the same result as adding the option tree color black,
00:28:09to the sum of option tree color orange,
00:28:12with option tree color pink.
00:28:15And this is how we just changed option,
00:28:18to not only behave like a monoid,
00:28:22It's time to have a look at the code from the source,
00:28:25from the originals,
00:28:28from where this revolution in functional programming started.
00:28:32And that is of course going back to Haskell.
00:28:35And from there we can see where these ideas have come from.
00:28:38In this project I have in the meantime,
00:28:41added more examples,
00:28:44and now we have a new folder,
00:28:48which is the folder that has monoids in it.
00:28:51Seven examples, and we are having a look at them right now.
00:28:54The first example is this one, monoid example.
00:28:57And in the monoid example,
00:29:00we are going to create a custom monoid.
00:29:03This is something that we can easily do in Haskell,
00:29:07and that is with the use of semigroup,
00:29:10which is a type that is specifically created to make our own monoids.
00:29:13And also we can find the monoid declaration for character.
00:29:16And also we can find the monoid declaration for character.
00:29:20Now character is our custom type,
00:29:23and we now have to understand a few syntaxes related to Haskell
00:29:26to be able to continue to understand this example.
00:29:29In this first part we are declaring a data class,
00:29:32which is named character.
00:29:36And character has two different properties.
00:29:39These are name and age,
00:29:42and we need to derive them of course from show and generic.
00:29:45Then we need to define our character as a semigroup type.
00:29:48What we need to do is establish different kind of paths for our code
00:29:52that will define our monoid.
00:29:55In the first line we can see this operator.
00:29:58And now I have to explain what this operator is.
00:30:01This is also called the monoidal append operator,
00:30:04or the mappend operator.
00:30:08The mappend operator in this line is defined
00:30:11to return a second character
00:30:14when the first character is of this type.
00:30:18In the second line it's the reverse,
00:30:21and on the third line we create a combination of two different characters.
00:30:24We define this ourselves.
00:30:28Another way that this operator is also commonly referred to
00:30:31is as a combinator,
00:30:34because it does combine two different operands.
00:30:37In this case we have this operand, which is character 1,
00:30:40this operand, which is character 2,
00:30:44and the combination of the two characters
00:30:47will see that the new name will be
00:30:50a concatenation of name1 and name2
00:30:53with a space between them,
00:30:56and the age will be the sum of the two characters.
00:30:59But this only defines the semigroup,
00:31:03which is where we define the results of the different operations,
00:31:06of the different combinations that we expect to find
00:31:09when calculating this result.
00:31:12And just below it we see the definition
00:31:15of a monoid type for character,
00:31:18and it shouldn't be surprising now to learn
00:31:22that Haskell does have a monoid type,
00:31:25which is where monoids come from,
00:31:28because the monoid type asks us to define a mempty and a mappend.
00:31:31Now we already know what a mappend is,
00:31:34this is a monoidal append operator,
00:31:38but mempty is our identity character.
00:31:41Mempty is an interesting property of monoids in Haskell,
00:31:44because we can automatically have it defined for us,
00:31:47and sometimes we need to custom make it,
00:31:50which is what we see here for our custom character,
00:31:53that now is also a monoid and a semigroup.
00:31:57We define mempty as a character with no name,
00:32:00or better said an empty name string,
00:32:03and aged 0 years.
00:32:06And then we define our monoidal append operator,
00:32:09or our mappend operator,
00:32:13which we say that it's this one.
00:32:16There are other possibilities for these operators,
00:32:20but for now for this series let's just stick to this one,
00:32:23which is our binary operator also,
00:32:26and it is composed of the lower than
00:32:29and the greater than symbols combined together.
00:32:32And then finally we can see our example in the function main,
00:32:36and in main we have a character,
00:32:39the first character is called the smith,
00:32:42which is where I think these characters come from by the way.
00:32:45The second character is character Lilith,
00:32:48and it has an age of 1000.
00:32:51So there will be a combined character,
00:32:55which will be the combination of character 1 and character 2.
00:32:58We also say that we have an empty character,
00:33:01which is simply the mempty of type character.
00:33:04This will result in character 0,
00:33:07with name empty.
00:33:11And then we also have the combined character 1 with empty
00:33:14and the combined character 2 with empty.
00:33:17These are just characters to test mempty,
00:33:20in other words to test our identity.
00:33:24So in this case we get a combined character 1 with empty,
00:33:27that is the result of combining character 1 with empty,
00:33:30and then we have combined character 2 with empty,
00:33:33which is a combination of mempty and character 2.
00:33:36And of course this one will result in character 1,
00:33:39and this one will result in character 2.
00:33:43And then we can print all of these variables to the console
00:33:46and see what happens.
00:33:49Shall we do that now? Let's do it.
00:33:52So if we go to Monoids in this project,
00:33:55and then run ghc1 MonoidExample.hs,
00:33:59then we will have our binary,
00:34:02and then we can run it.
00:34:05And then here we can see
00:34:08that we get character 1,
00:34:11which is the smith with an age of 2000 years,
00:34:15character 2, which is Lilith with an age of 1000,
00:34:18character with empty 1,
00:34:21which is still the smith with age 2000,
00:34:24and character with empty 2,
00:34:27which is Lilith with age 1000.
00:34:31But then we have the magic of Monoids,
00:34:34which is that we get our combined character,
00:34:37which is Lilith with an age of 3000.
00:34:40The first is a concatenation,
00:34:43and the second one is the result of the sum of the two ages.
00:34:46Finally at the end we print our entity,
00:34:50and our entity is our mempty,
00:34:53and our mempty is an empty character with a name empty and age 0.
00:34:56So now let's have a look at one example that is very simple.
00:34:59This is List.
00:35:02We have established already that in Kotlin a list is already a Monoid.
00:35:05Well, if you see that the example is here,
00:35:09you can already be assured that List is also a Monoid in Haskell.
00:35:12But let's see the difference between a custom Monoid
00:35:15and an already implemented Monoid in the Haskell libraries.
00:35:18It's just this.
00:35:21So we don't need to make anything to turn a List into a Monoid,
00:35:25because it is already a Monoid.
00:35:28And if we check on List1,
00:35:31we see that List1 is composed of 1, 2 and 3,
00:35:34and List2 is composed of 6.
00:35:37When we combine the two lists,
00:35:40we should have a concatenation of the two lists,
00:35:44which is also a name that this operator gets called to frequently.
00:35:47List1 empty is again the same test for the identity,
00:35:50List1 combined with mempty,
00:35:53and then List2 empty is mempty combined with List2,
00:35:56just to see if the order plays any role here.
00:36:00If we now run example2,
00:36:03we just need to run ghc2hs,
00:36:06now we get our binary,
00:36:09and then we just need to run to MonoidList.
00:36:12And there we see that we get List1,
00:36:161, 2, 3, that's the first printout.
00:36:19Then we get List2,
00:36:22which is 4, 5, 6.
00:36:25List1 with empty returns, of course, List1,
00:36:28and List2 with empty returns, of course, List2.
00:36:32But what is our mempty here?
00:36:36Let's have a look.
00:36:39Let's say that we do a putString,
00:36:42newLine, and then we say
00:36:45identity.
00:36:48Which one is our identity?
00:36:52As I'm writing this, you probably already know what it is
00:36:55for a list.
00:36:58It shouldn't be hard, it should be an empty list.
00:37:02So let's see what happens.
00:37:05We get an error here,
00:37:08and I did this on purpose, because mempty is actually a call.
00:37:11We need to define our identity.
00:37:15We need to specify the type that our identity has.
00:37:18And in this case, the type is a list.
00:37:21But list, not list written as list,
00:37:24instead, with square brackets,
00:37:27and then we need to define that our list is of type int.
00:37:31But this isn't enough, because we are defining here a type,
00:37:34and so we need to put this inside of parentheses.
00:37:37And so if we now run this,
00:37:40we see that the result is what we had before,
00:37:43except that now, at the end, we see our entity printed out to the console.
00:37:47And finally, we can now have a look at monads.
00:37:50And how do we define monads, and what do they mean?
00:37:53There are six rules that define what they are.
00:37:56And for that, one of the things that we can do
00:37:59is look at sites that talk about that.
00:38:02And one of them is the site of the Faculdade de Ciências da Universidade do Porto.
00:38:06And here we have an interesting post
00:38:09from Pedro Vasconcelos,
00:38:12that's the one that's over here,
00:38:15where it is described what a monad is and how it works.
00:38:18This document is based, what it says here,
00:38:22from the Monads for Functional Programming document
00:38:25originally made by Philip Wadler in 2001,
00:38:29we can download the PDF over here, and this is the link to it.
00:38:32And here we can find what are monads for functional programming.
00:38:35There are examples here in Haskell that we can have a look at,
00:38:38but it's time now to have a look at all of these definitions.
00:38:41And one of the first definitions is that
00:38:45a monad must have a type constructor.
00:38:48And a type constructor is a constructor where we need to define a type.
00:38:51So it's just a very simple definition.
00:38:54And if we think of a monad like list,
00:38:57we can see that when we create a list,
00:39:00we need to have some way of defining which type a list has.
00:39:04So if we have a list of numbers,
00:39:07normally that list of numbers gets automatically defined as a list of integers,
00:39:10but it can be a list of anything, a list of strings,
00:39:13or any other kind of list.
00:39:16And that is basically what a type constructor is.
00:39:20This is a common property for other different types as well,
00:39:23not specifically to monads,
00:39:26but the type that we are evaluating if it is a monad or not.
00:39:29One other thing that the document describes is that
00:39:32it needs to have two operations.
00:39:35The first operation that is described over here is the return,
00:39:39and the second is the bind operation.
00:39:42The return operation here makes a reference to how we in Haskell can define
00:39:45giving a monadic context to a value.
00:39:48This is something that in Kotlin is akin to just saying list of.
00:39:51When we do a list of and create a list from numbers,
00:39:54that is equivalent to this return in Haskell.
00:39:58Maybe not exactly the same,
00:40:01but it is essentially one operation that is very similar
00:40:04to the return operation in Haskell.
00:40:07Then it mentions the operation bind.
00:40:10The operation bind is akin to what we in Kotlin call the flatMap,
00:40:14and with bind we can flatMap a monadic type.
00:40:17And if we look at this,
00:40:20we can see that this is a monadic type.
00:40:23And if we look at this particular definition over here,
00:40:27we see that it says that
00:40:30a return of a is equivalent to
00:40:33giving a type constructor m a value a.
00:40:36So that means that we give a monadic context to value a.
00:40:39So that means that we give a monadic context to value a.
00:40:43And here is the same, the bind operation
00:40:46that returns a monadic context.
00:40:49It only means that we are simply creating
00:40:52an operation that uses a function
00:40:55to transform whatever monadic value
00:40:58we put it through,
00:41:02and when we add a monadic context
00:41:05to whatever we create inside that function
00:41:08that receives as a receiver the actual value,
00:41:11it will return another value
00:41:14wrapped around a monadic context.
00:41:18It sounds complicated, but it really is simple to understand
00:41:21if we think about what flatMap in Kotlin does.
00:41:24So in Kotlin when we have a list of lists,
00:41:27each one of those lists
00:41:31that are part of the larger group of lists
00:41:34has several numbers.
00:41:37When we apply a flatMap to it
00:41:40and don't do any particular operation
00:41:43and simply flatMap whatever the receiver is,
00:41:47then we end up getting a result that has a monadic context.
00:41:50We get a list of numbers in the receiver
00:41:53where then the flatMap operation
00:41:56will result in having only a list of numbers
00:41:59with all of these numbers that were contained
00:42:03in all of the different lists of the major group
00:42:06that is also a list.
00:42:09And that's where we come to this point,
00:42:12monads in Haskell,
00:42:15where there is a simple definition of everything
00:42:18that a monad should have and what should it comply to.
00:42:22This is a class.
00:42:25In this definition we are saying that
00:42:28the monad that we are using of this type M
00:42:31is a type constructor,
00:42:34and in its definition it needs to have
00:42:38the return operation, this one over here,
00:42:41which is also known as a unit,
00:42:44and this bind operation,
00:42:47but if we go further down we see that there are
00:42:51three more properties that are very important
00:42:54and they are actually called laws.
00:42:57And described in this document there are three laws.
00:43:00These are the generic laws that monads must comply
00:43:03to be called a monad.
00:43:07The left identity property, the right identity property
00:43:10and the associativity property.
00:43:13The associativity property is very similar
00:43:16and the associativity property is very different
00:43:19but the principle behind it is very similar.
00:43:22For each one of these properties let's have a look
00:43:26at examples in Kotlin as we talk about them.
00:43:29Before I explain what this means in left identity,
00:43:32let's first have a look at the unit test
00:43:35that checks for and tests the left identity
00:43:38of the monad list.
00:43:42And we can already assume that a list is a monad.
00:43:45So let's test the left identity law of the monad
00:43:48and let's bear in mind that this is the left identity
00:43:51and I will explain in a bit why this is called left identity
00:43:54but I can only do that when I explain the right identity as well.
00:43:57Then we will see the difference between the two of them.
00:44:01So in this case we are creating a tree over here
00:44:04and we are creating a function that will receive the tree
00:44:07and will set ten leaves to it.
00:44:10Essentially creating a new tree with ten leaves
00:44:13per tree.
00:44:16But in this case the resulting tree with these ten leaves
00:44:20will be a modification of the tree that we have put in
00:44:23as an argument.
00:44:26Now we have a function that is function f
00:44:29and if we now use that function f in that flat map
00:44:32having prior created the monadic context
00:44:36around tree 1 and that is with list of
00:44:39and that is our unit function
00:44:42then we should be getting the same result as a function of a tree.
00:44:45f of tree 1 should be exactly the same
00:44:49as list of tree flat map f.
00:44:52This tests the left identity law.
00:44:55Let's run it to see if it goes successfully
00:44:58and we get a successful result
00:45:01and so in short
00:45:05this means that we had a tree, we created a list with it
00:45:08we flat mapped it with function f
00:45:11that creates a new tree with ten leaves based on the first one
00:45:14and then we should get the same result with that
00:45:17as calling the function f with argument tree 1.
00:45:21But this is the left entity.
00:45:24The right entity tests something a bit different
00:45:27and we can see here in the test
00:45:30if we just analyze the test
00:45:33we see that we get a tree 1
00:45:37and then we create a list of that tree 1
00:45:40or a list of one tree
00:45:43and then we flat map those trees directly
00:45:46using the unit function to create a monadic context
00:45:49around our value
00:45:52and then that gets flat mapped
00:45:56and it should result in the trees from the beginning.
00:45:59What is the difference between this right identity law
00:46:02and the left identity law?
00:46:05From this code we can just infer
00:46:09but that's not the whole story.
00:46:12So for that let's go back to the documentation
00:46:15but here's the thing, in the meantime
00:46:19I've already changed that documentation
00:46:22and now I'm using the slides that I have created
00:46:25based on the documentation that I have shown
00:46:28throughout the videos that you have seen in this playlist
00:46:31and so let's have a look at the slides now.
00:46:35In this slide we see the definition of monads
00:46:38which is a monad type constructor.
00:46:41The unit is our list of
00:46:44which is now represented here with this return of a
00:46:47which gives it a monadic context
00:46:50analogous to list of
00:46:54which then returns a inside a monadic context
00:46:57which in this case is m.
00:47:00This is equivalent to do a list of a.
00:47:03Then we've got the bind operator
00:47:06in this case the bind operator is this one over here
00:47:09for Haskell
00:47:13and what we see is that when we use the bind operator
00:47:16what happens is that we use value a inside a monadic context
00:47:19we put it through the bind operator
00:47:22essentially flat mapping
00:47:25and then we use the value a directly
00:47:29to change whatever we want
00:47:32or to create whatever we want
00:47:35to use the monadic context as the initial value
00:47:38that's wrapped inside that monadic context
00:47:41and as a result we get b
00:47:44which is another result, another value
00:47:48which is also wrapped in the monadic context
00:47:51this is akin to having a list of something
00:47:54that gets transformed
00:47:57and then finally after flat mapping
00:48:00it comes up with another value in another monadic context
00:48:03we see here a similarity and already a difference
00:48:07between monads and functors
00:48:10if you remember from functors
00:48:13it was kind of like doing the operation ma to mb directly
00:48:16so it was a one to one transformation
00:48:19in this case we're not doing that
00:48:23in this case we need to have a value
00:48:26wrapped inside a monadic context
00:48:29to perform the flat map
00:48:33and the two laws that we have seen in action
00:48:36are the left identity law
00:48:39which is this one over here
00:48:42that says that the return of a
00:48:46which means the list of a
00:48:49when flat mapped with function f
00:48:52should be the same as calling function f directly
00:48:55with value a
00:48:58which we have seen in our Kotlin code
00:49:01and for the right identity law
00:49:05we have seen that if we have a value a
00:49:08wrapped in a monadic context
00:49:11and then we flat map it
00:49:14and use simply a return
00:49:17that is the value wrapped in a monadic context
00:49:21but without any single transformation
00:49:24we should get the same thing as an output
00:49:27so we get a
00:49:30inside a monadic context in the same way as before
00:49:33which is what we saw here when we flat map a list of it
00:49:36in this case
00:49:40essentially coming from a list of trees
00:49:43flat mapping the result of creating a list of one tree
00:49:46should get us the trees
00:49:49the reason why they are right and left
00:49:52or in this case left and right identity laws
00:49:56is because the return a
00:49:59is on the left and the return here is on the right
00:50:02of the flat map operator
00:50:05in this case the bind operator in Haskell
00:50:08the last property that we look at
00:50:11in this case is associativity
00:50:15so let's go back to our Kotlin code and see that in action
00:50:18in our Kotlin code we have a last test
00:50:21one last test that says
00:50:24should test associativity of a monad
00:50:27so first we create a tree
00:50:30then we create a list of trees with one tree
00:50:34then we create a function that will use a tree
00:50:37and transform it to another list of trees
00:50:40and then we have a function g
00:50:43that will transform the input tree
00:50:46and will just give it one leaf
00:50:50removing all the other leaves that it had before
00:50:53essentially creating a copy of itself
00:50:56the idea is to get to this last expression
00:50:59where we are testing
00:51:02if we flat map the trees with function f
00:51:05and then flat map the result with function g
00:51:09we should always get the same result
00:51:12as if we flat map the trees
00:51:15and then use the value passed
00:51:18from that flat map
00:51:21with function f
00:51:25to create a result that we can then flat map to g
00:51:28inside of the definition of the function
00:51:31that we are using for this flat map
00:51:34both this result and this result
00:51:37should return the same
00:51:41and that is the way we can define associativity
00:51:44of a monad in this case
00:51:47so if we run the test it should run successfully
00:51:50and it should run as successfully
00:51:53so we run the right identity test
00:51:56which I didn't run before but I will run now
00:52:00and so we have proven now the left identity
00:52:03the right identity, the associativity
00:52:06we have seen that there is a bind operator
00:52:09we have seen there is a type constructor
00:52:12and we have seen that there is a unit function
00:52:16just as we have seen here in our slide
00:52:19where we see that unit is also called a monadic return
00:52:22and this is the rule that establish it
00:52:25so the rule says that when we have value a
00:52:28again wrapped in a monadic context
00:52:32and we flat map it with function f
00:52:35and then we flat map the result with function g
00:52:38it should be the same as the same process
00:52:41but when we flat map it
00:52:44we flat map it with another function
00:52:48which is using function f
00:52:51inside of that function
00:52:54to flat map the result with function g
00:52:57so when we change the order
00:53:00the result should not be affected
00:53:03that is probably the simplest way to say it
00:53:07no matter how we associate the different flat maps
00:53:10it should always turn out to be the same result
00:53:13now this of course is for Kotlin
00:53:16but we should also have a quick look
00:53:20at the example in Haskell
00:53:23where these things originally come from
00:53:26so in our Haskell test drives project
00:53:30there is a folder called monads
00:53:33and inside the monads folder
00:53:36there are a lot of examples
00:53:39but we are only having a look at list for now
00:53:42and this is list
00:53:46this is the example for list
00:53:49and this in Haskell as you have seen before
00:53:52is a definition of a function
00:53:55this is the implementation creation of that function
00:53:58the same way over here and the same way over here
00:54:01now we have two functions
00:54:05one is called create two element function
00:54:08and the other one is create double element function
00:54:11the first function simply creates an array of values
00:54:14based on the first value that is given as an input
00:54:17the actual value that comes in
00:54:20and the other one is the addition of one to that value
00:54:24and then we return an array of two values
00:54:27the create double element function
00:54:30simply multiplies the input argument
00:54:33and multiplies by two, essentially just doubling it
00:54:36this is all followed by two tests
00:54:40the left identity test and the right identity test
00:54:43these two are also functions
00:54:47because what we are doing inside of the test
00:54:50is using the return to create a list with value a
00:54:53and then we flat map that
00:54:56and then we see using create two element function
00:54:59will result in the same result
00:55:03as calling the create two element function
00:55:06with the input argument a
00:55:09the right identity test function is the same
00:55:12except that it receives as an input parameter
00:55:15one value or more and it returns a boolean
00:55:18because it is testing if the value that we receive
00:55:22value m, which is already wrapped in the monadic context
00:55:25is the same when having applied a flat map
00:55:28directly to it and simply using a return on it
00:55:31will return the same value in that monadic context
00:55:34as we have seen before
00:55:38this is the right identity law of the monads
00:55:41so we've got a test for the left identity law of the monads
00:55:44and for the right identity law of the monads
00:55:47and further down we have a few other examples
00:55:50but these are not mandatory properties for a monad
00:55:54maybe a subject for a next video
00:55:57but for now what's important here is that we understand
00:56:00what this test is doing
00:56:03so if we read the main function from top to bottom
00:56:06we see that we first create a test value
00:56:10which is an integer of value 5
00:56:13and a list of lists which is 1, 2, 3, 4, 5, 6, 7, 8, 9
00:56:16and then this is followed by several printouts
00:56:19in the first printout we see that we are simply
00:56:22printing out the return of test value
00:56:25this should create a list of integers
00:56:29with one element
00:56:32that's what this whole thing here does
00:56:35in the second operation we are just printing out
00:56:38the result of a flat map operation on the test list
00:56:41so the test list is a list composed of 1, 2 and 3
00:56:44these are three integers
00:56:48and then we apply this flat map operator
00:56:51and then what we do inside of it
00:56:54is that we get the element of our list as an argument
00:56:57without a monadic context
00:57:00and then we turn that into a list
00:57:04therefore giving it a monadic context
00:57:07where we multiply every element by 2
00:57:10on the output here we should be getting a list of 2, 4 and 6
00:57:13after this example there is another one
00:57:16which is another flat map operation
00:57:19and this one does a flat map of the list of lists
00:57:23and this list of lists is what we saw here
00:57:26a list of lists composed of three lists
00:57:29where the first one has 1, 2, 3
00:57:32the second one has 4, 5 and 6
00:57:35and the third one has 7, 8 and 9
00:57:38the flat map on this operation
00:57:42we should be getting for an x value
00:57:45each one of these lists
00:57:48that then immediately returns
00:57:51and therefore the result of this flat map
00:57:54is what we are used to seeing in Kotlin
00:57:58when we do a flat map
00:58:01and that is that all of this list
00:58:04will be turned into one single list
00:58:07and what we do here is simply calling the left identity
00:58:10as we have seen before with the test value
00:58:13in this case is 5
00:58:17and this will test, if we go back to the top
00:58:20it will simply test that when we get here a 5
00:58:23it will then do a return of it
00:58:26that means this will be a list
00:58:29where we then apply a flat map
00:58:33and then we will get a result
00:58:36and when the flat map returns
00:58:39that result should be the same
00:58:42as calling the createTwoElement function with value a
00:58:45in this case the value a will be 5
00:58:48and therefore the result will be again the array of 5 and 6
00:58:52after that we test the right identity law for the monad
00:58:55and in this case we put through the test list
00:58:58if we go back to the top
00:59:01and we see the right identity test
00:59:04we use that list to apply a flat map to it
00:59:07and we return it without making any transformation
00:59:11so in that case the result should be again the list itself
00:59:14and then to complete all the tests
00:59:17that prove that this is a monad
00:59:20we call the associativity test
00:59:23I didn't mention the associativity test
00:59:27because I had put the bonus above the associativity test function
00:59:30so we can now have a look at it
00:59:34we receive it over here, this will be our m
00:59:37that is a monadic context
00:59:40and this will simply test what we have seen before
00:59:43when we make different calls to a flat map
00:59:46under different kind of associations between them
00:59:50so on the left hand side of this equal operation
00:59:53we apply the flat map directly to m
00:59:56with function createTwoElement function
00:59:59then we apply flat map again
01:00:02to the result of that operation
01:00:05with function createDoubleElement function
01:00:09which should be the same as applying the flat map
01:00:12with another function that we create on the fly
01:00:15that consists of calling the createTwoElement function
01:00:18directly on x
01:00:21and then applying the flat map on that
01:00:25with the createDoubleElement function
01:00:28so that means that we create a TwoElement function
01:00:31to it, therefore as a final result
01:00:34we should just be getting a list that has been doubled
01:00:37and also has more elements to it
01:00:40both for the first case and for the second case
01:00:44we will not see the results of these transformations
01:00:47but we will see that the assertions will all be true
01:00:50and to see the result of these operations
01:00:53of course ignoring the bonus tests
01:00:56but remember that they do exist
01:00:59we now only have to build our example
01:01:03with ghc
01:01:06and after it has been compiled
01:01:09we only have to run it
01:01:12and there we see that all of these operations
01:01:15turn out to be true
01:01:19and we see the result of the first operation
01:01:22which is we create simply an array with 5
01:01:25using return
01:01:28and we use the flat map operation
01:01:31simply to double all the values inside that original array
01:01:34then we just use the flat map operation
01:01:38on the list of lists to finally get a result
01:01:41of 1, 2, 3, 4, 5, 6, 7, 8, 9
01:01:44which is the merge of all of those lists into one
01:01:47in other words
01:01:50finally we see that the left identity works
01:01:54with number 5, we see that the right identity works
01:01:57and because of this we were able to prove that a list
01:02:00is also a monad in Haskell
01:02:03if we go back to our slide
01:02:06this is what we've proven both in Kotlin
01:02:09and in Haskell at this point
01:02:13we've seen that both of them have a type constructor
01:02:16list has a type constructor also in Haskell
01:02:19there is a unit or a monadic return for Haskell
01:02:22and also for Kotlin
01:02:25there is a left identity law and a right identity law
01:02:28for both cases and there is an associativity law
01:02:32where they both comply to
01:02:35so this is essentially what monads are
01:02:38in the project Haskell test drives
01:02:41there are a lot of other projects that you can also have a look at
01:02:44I have examples here with Eider
01:02:48examples with Maybe
01:02:51and other custom examples
01:02:54of how monads work and how they are built
01:02:57but before we conclude this presentation
01:03:00it's also nice to have a look at this example
01:03:03the monad custom because this is where we can build
01:03:07our own monad version in Haskell
01:03:10and Haskell is great in that because in Haskell
01:03:13the instance monad does exist
01:03:16this monad type exists and we can use it to define our types
01:03:19in this case I am creating a box
01:03:22and here we define that our box is also an applicative
01:03:26and we define it as being pure
01:03:29and then we simply define it as being a monad
01:03:32by saying that the return is pure
01:03:35and that this is how we define the mapping operation
01:03:38and the bind operation in this case simply receives a box
01:03:42which is our monadic type with value x
01:03:45and then we define that we use function f
01:03:48for the flat map operation
01:03:52here we define a simple test function
01:03:55just to be able to work with our box
01:03:58and this box function is simply a function that receives an x
01:04:01and then uses that x to double it
01:04:04and then create a box with it
01:04:08thus creating a new monadic context
01:04:11therefore to make our test we create a boxed value
01:04:14with value 5 on it and then we try to flat map it
01:04:17with the box function
01:04:20the flat map uses a function that creates a monadic context
01:04:23to the value that is passed through
01:04:27therefore when we print the boxed value right now
01:04:30we should get a box of number 10
01:04:33so if we build it
01:04:36and then we run it
01:04:39we see predictably
01:04:43that we get a box with number 10
01:04:50then we print
01:05:15as a short disclaimer I'd like to mention that I'm not associated
01:05:18with any of the brands eventually shown, displayed or mentioned in this video.