Lets start with an example, imagine that you are writing code to control a robot. You want to be able to do something like:
forward(5)
raiseArm(5)
however, your program needs to be single threaded, and needs to quickly respond to the shutoff command. One solution would be to make every function exits quickly, and gets called in a loop until its done. This means that every function is essentially an object with the methods: init(), step(), where step returns true when the action is finished.
Suppose we define forward(int) and raiseArm(int) as described. We would like to be able to easily define a function that moves forward then raises the arm. This new function would be combined(a,b)=forward(a) >> raiseArm(b).
Now, imagine we have a function that moves forward until it hits a wall, then returns the distance traveled. We want to move forward until we hit a wall, then return to our initial position. If we could block this would look like:
x=forwardUntilWall()
backward(x)
Instead of having forwardUntilWall() return x, it can store x in itself and let the bind operator pass it to the init function of backward(). This would let us write the above as:
forwardUntilWall() `bind` backward.
Using do-notation (which is just syntactic sugar), we could also write that as:
do
x<-forwardUntilWall()
backward(x)
Which looks a lot like our blocking version.
Imagine that you have a function setArm, and you want to set your arm sequentially at variuas posistions. Normally you would do:
for (each x in posistions):
setArm(x)
Using monads, you could do:
forEach (posistions) (setArm)
or using do-notations:
forEach (posistions) $ \x-> do
setArm(x)
In Haskell, forEach is called "forM_", and needs to be imported from Control.Monad.Loops. Of course you could avoid importing it and simply define it yourself.
Also, we are not restricted to combining our specific monad with only the general monadic operators. For example, we can easily define a function that will take 2 monadic operations and return a monadic operation that runs both of them concurrently.
Suppose we define forward(int) and raiseArm(int) as described. We would like to be able to easily define a function that moves forward then raises the arm. This new function would be combined(a,b)=forward(a) >> raiseArm(b).
Now, imagine we have a function that moves forward until it hits a wall, then returns the distance traveled. We want to move forward until we hit a wall, then return to our initial position. If we could block this would look like:
Instead of having forwardUntilWall() return x, it can store x in itself and let the bind operator pass it to the init function of backward(). This would let us write the above as: Using do-notation (which is just syntactic sugar), we could also write that as:do x<-forwardUntilWall() backward(x)
Which looks a lot like our blocking version.
Imagine that you have a function setArm, and you want to set your arm sequentially at variuas posistions. Normally you would do:
Using monads, you could do: or using do-notations: In Haskell, forEach is called "forM_", and needs to be imported from Control.Monad.Loops. Of course you could avoid importing it and simply define it yourself.Also, we are not restricted to combining our specific monad with only the general monadic operators. For example, we can easily define a function that will take 2 monadic operations and return a monadic operation that runs both of them concurrently.