Scared of monads? Just not getting them?
Well..., you are not alone!
I have just stumbled over this awesome video demystifying monads by Dr. Brian Beckman which you can check out here.
After being done with it I felt the urge to revisit Haskell (which I sadly have left alone since my AoC2021) to just try out what he taught.
So here is a small example in Haskell for anyone that also greatly benefits/learns by coding the actual concept, rather than solely witnessing it.
-- THIS COVERS FIRST PART OF THE VIDEO.
-- Where we have functions of type a -> Ma
-- We created these functions with their corresponding types:
-- createListWithItem a -> Ma
-- addOneAndCreateListWithItem a -> Ma
-- doubleValueAndCreateListWithIt a -> Ma
-- doInsanceCalculation a -> Ma
-- This function has a -> Ma type from the video.
-- [] is a list in Haskell. Which is built as a Monad.
-- So our Monad type will be [] instead of M from the video.
createListWithItem :: a -> [a]
createListWithItem x = [x]
-- same as createListWithItem applies here.
addOneAndCreateListWithItem :: a -> [a]
addOneAndCreateListWithItem x = [x+1]
-- same as createListWithItem applies here.
doubleValueAndCreateListWithIt :: a -> [a]
doubleValueAndCreateListWithIt x = [x*2]
-- same as createListWithItem applies here.
doInsanceCalculation :: a -> [a]
doInsanceCalculation x = [(x + 1) * 3]
-- This function basicly has a -> Ma type from the video.
-- Here we see how we can puzzle our little building blocks together to realize
-- seemingly complex logic.
-- Ensuring the resulting type in compile time.
-- Composing as we need.
shoveIt :: a -> [a]
shoveIt a = createListWithItem a
>>= addOneAndCreateListWithItem
>>= doubleValueAndCreateListWithIt
>>= doInsanceCalculation
-- The following is just synctactic sugar for the functon above. (Besides the if else)
-- That demonstrates that while every computation uses the previous value it
-- does not mutate it. Meaning in every step we take we have access to all
-- previous results. It is called "do notation".
shoveIt2 a = do
x1 <- createListWithItem a
x2 <- addOneAndCreateListWithItem x1
x3 <- doInsanceCalculation x2
if even x3 then return x3 else return x1
The source code can also be found here.

Whats the point of these monads?
- Well, in my understanding, they are just a tool to make development easier.
They:
- make code consice/clear
- allow the developer to use common syntax (e.g. shove/bind as seen above) for any data type that is a monad. No matter what the logic behind the specific monad really means.
- give the developer a clear intuition about the code, by just seeing their data type. Some examples:
-- Without seeing ANY implementation detail, we already now:
-- This is a function with a computation that might fail. Thats it. The Maybe
-- monad.
fn1 :: a -> Maybe a
-- Again, without seeing ANY implementation details, we already now:
-- This is a function that uses side effects(IO) e.g. reads from std input and
-- might return an Integer. Thats it.
fn2 :: a -> IO Maybe Int
I hope you learned something today! See you soon! :]