Haskell Monads Guide — Monad Typeclass, do Notation, and Common Monads
In this tutorial, you will learn about Haskell Monads Guide. We cover key concepts, practical examples, and best practices to help you master this topic.
Haskell Monad typeclass extends Applicative with (>>=) (bind) for chaining effectful operations where each step can depend on the previous result -- with do notation providing readable imperative-style syntax for monadic code.
Monad Typeclass
class Applicative m => Monad m where
(>>=) :: m a -> (a -> m b) -> m b
return :: a -> m a -- same as pure
-- Laws:
-- return x >>= f = f x
-- m >>= return = m
-- (m >>= f) >>= g = m >>= (\x -> f x >>= g)
Maybe Monad
-- Safe division chain
safeDiv :: Int -> Int -> Maybe Int
safeDiv _ 0 = Nothing
safeDiv x y = Just (x `div` y)
compute = do
a <- safeDiv 10 2
b <- safeDiv a 3
c <- safeDiv b 0 -- Nothing here
return c
-- Using (>>=)
compute' = safeDiv 10 2 >>= \a ->
safeDiv a 3 >>= \b ->
safeDiv b 0
List Monad
-- Nondeterministic computation
pairs = do
x <- [1,2,3]
y <- [4,5]
return (x, y)
-- [(1,4),(1,5),(2,4),(2,5),(3,4),(3,5)]
-- With guard
evenPairs = do
x <- [1..10]
guard (even x)
y <- [1..10]
guard (y > x)
return (x, y)
Either Monad
-- Error handling with Either
type Error = String
validateAge :: Int -> Either Error Int
validateAge n
| n < 0 = Left "Negative age"
| n > 150 = Left "Age too high"
| otherwise = Right n
validateName :: String -> Either Error String
validateName "" = Left "Empty name"
validateName n = Right n
process = do
name <- validateName "Alice"
age <- validateAge 30
return (name, age)
-- Right ("Alice", 30)
IO Monad
main :: IO ()
main = do
putStrLn "Enter your name:"
name <- getLine
putStrLn $ "Hello, " ++ name ++ "!"
content <- readFile "data.txt"
writeFile "output.txt" content
Common Mistakes
1. Forgetting return
In do notation, the last line must be an expression of the monadic type. Use return to wrap pure values: return (x + y).
2. Using return unnecessarily in pure code
return has no special meaning in Haskell -- it just wraps a value. Don't use it in non-monadic code.
3. Confusing (>>=) with (>>)
(>>) ignores the result: action1 >> action2 runs action1, then action2. Use when you only need the side effects.
Practice Questions
1. What does (>>=) do? Bind: extracts a value from a monadic context and passes it to a function that returns a new monadic value.
2. What is do notation syntactic sugar for?
Using (>>=) and (>>). do { x <- a; b } becomes a >>= \x -> b.
3. What is the difference between Maybe and Either as Monads? Maybe short-circuits on Nothing. Either short-circuits on Left. Either carries an error value; Maybe carries nothing.
FAQ
{{< faq question="What are the Monad laws?" >}}
Left identity: return x >>= f = f x. Right identity: m >>= return = m. Associativity: (m >>= f) >>= g = m >>= (\x -> f x >>= g).
{{< /faq >}}
{{< faq question="What is the Writer monad?" >}}
Writer accumulates a log or output alongside a value: Writer w a where w is a monoid for accumulation.
{{< /faq >}}
{{< faq question="What is the State monad?" >}}
State threads a state value through computations: do { modify (+1); x <- get; put (x * 2) }.
{{< /faq >}}
What's Next
Now learn about IO in Haskell.
| Topic | Description | Link |
|---|---|---|
| IO | Input/output operations | {{< ref "12-io" >}} |
| Records | Data record syntax | {{< ref "13-records" >}} |
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro