Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Monads for Control Flow - Sequence, Selection and Iteration

I can see how you'd use a Monad is Haskell for IO - to create a container around the computation for this operation. It makes sense that you can use Monads to 'plug computations together' - as you would compose functions for a dataflow operation.

What I'm only just grokking is that you can use Monads for Control Flow. Now I understand Control flow to be about Sequence, Selection and Iteration. Now I'm comfortable with higher order functions like map, foldl, filter and zipwith/mapcat to perform operations on lists.

My question is - can I do sequence, selection and iteration with monads in order to achieve control flow? (Happy for an answer in Haskell, Scala or Clojure)

like image 475
hawkeye Avatar asked Nov 24 '13 03:11

hawkeye


People also ask

What are monads explain with example?

In functional programming, a monad is a software design pattern with a structure that combines program fragments (functions) and wraps their return values in a type with additional computation.

What are monads used for?

A monad is an algebraic structure in category theory, and in Haskell it is used to describe computations as sequences of steps, and to handle side effects such as state and IO. Monads are abstract, and they have many useful concrete instances. Monads provide a way to structure a program.

What are the different classes of monads?

Common monadsNondeterminism using List monad to represent carrying multiple values. State using State monad. Read-only environment using Reader monad. I/O using IO monad.


1 Answers

For sequencing in Haskell, you have the functions >>= and sequence:

(>>=) :: Monad m => m a -> (a -> m b) -> m b
sequence :: Monad m => [m a] -> m [a]

The >>= or bind function takes a monadic action, extracts the value from it and feeds it into a function that returns a new monadic action. The sequence function takes a list of monadic actions of the same type and executes all of them, aggregating their results and wrapping it as a single action.

For iteration you have mapM and forM (forM = flip mapM)

mapM :: Monad m => (a -> m b) -> [a] -> m [b]

The mapM and forM functions are for applying a function that returns an action to each element in a list, aggregating the results as a single action.

For selection, I assume you mean conditionals, which are implemented in Haskell as just if-the-else expressions. They can be used directly in monadic expressions the same as they can be used in pure expressions. However, you can also use certain monads for performing choices or at least handling errors. The easiest to grok is the Maybe monad:

data Maybe a = Nothing | Just a

instance Monad Maybe where
    return a = Just a
    (Just a) >>= f = f a
    Nothing  >>= f = Nothing

It has a very simple implementation. Essentially, if you try to sequence a Nothing into anything else, it will return Nothing every time. This gives you the notion of short-circuited failure:

lookup :: Eq a => a -> [(a, b)] -> Maybe b
-- Looks up a value in a key-value association list

myFunc :: Int -> [(String, Int)] -> Maybe Int
myFunc mult assocList = do
    i <- lookup "foo" assocList
    j <- lookup "bar" assocList
    return $ i * mult + j

Here, if the lookup for "foo" fails, the myFunc immediately returns Nothing. Similarly if the lookup for "bar" fails, myFunc immediately returns Nothing. It's only when both lookups succeed does myFunc do any computation. This provides a sort of "error handling". There's a similar monad Either a

data Either a b = Left a | Right b

instance Monad (Either a) where
    return a = Right a
    (Right a) >>= f = f a
    (Left a)  >>= f = Left a

that works very much the same, except the "failure" value can carry some context, such as a string error message or the state of the computation at the point of failure.

like image 104
bheklilr Avatar answered Sep 24 '22 03:09

bheklilr