Monad

Contents
The bind operator
Maybe as a monad
The three laws
What a monad is not

The bind operator

A monad is a functor with a way to chain a step that itself returns a wrapped value. Without that, nesting grows one level per step:

class Applicative m => Monad m where (>>=) :: m a -> (a -> m b) -> m b Just 2 >>= \n -> Just (n + 1) -- Just 3 Nothing >>= \n -> Just (n + 1) -- Nothing

The shape m a -> (a -> m b) -> m b is the whole idea: take a value out of the context, feed it to a function that puts a new value back, and keep one layer instead of two.

Maybe as a monad

Three lookups in a row would need three nested cases. Bind flattens them and stops at the first failure:

find :: String -> [(String, Int)] -> Maybe Int find = lookup total = find "a" prices >>= \pa -> find "b" prices >>= \pb -> pure (pa + pb)

A missing "a" short-circuits everything after it. The types stay flat: the result is Maybe Int, not Maybe (Maybe Int).

The three laws

As with functors, the compiler does not check these. Every instance in the standard library obeys them, and yours must too:

-- left identity pure a >>= f == f a -- right identity m >>= pure == m -- associativity (m >>= f) >>= g == m >>= (\x -> f x >>= g)

The laws say that chaining groups however you like, which is what lets the compiler and the reader reorder a long chain without changing its meaning.

What a monad is not

A monad is not a way to escape purity and it is not a design pattern for state. It is an interface with three methods and three laws, and Maybe, lists, functions, and IO all happen to implement it:

-- the same operator, three different behaviours Just 1 >>= \x -> Just (x + 1) -- Just 2 [1,2] >>= \x -> [x, x * 10] -- [1,10,2,20] getLine >>= \s -> putStrLn s -- reads, then prints

The list instance runs the rest of the chain once per element, which is exactly what a comprehension does. Lesson 32 rewrites these examples in the notation designed for them.

Next: do notation

Article author: Arthur Isaev

Related articles
Haskell
Haskell course: zero to hero in 50 lessons
What is Haskell and why it matters
Install the toolchain with GHCup
GHCi: the interactive shell
Your first program
Values with let and where
Types and type signatures
Functions and application
Currying and partial application
Operators, sections, and fixity
if, guards, and pattern guards
case expressions
Pattern matching
Tuples
Lists
Ranges and enumeration
List comprehensions
Recursion replaces loops
map, filter, and foldr
Lambdas and composition
Type classes
Parametric polymorphism
Maybe and null safety
Either and recoverable errors
data: product types
data: sum types
Records
newtype and type synonyms
Recursive data: binary trees
Functor
Applicative
Monad
do notation
IO and purity
Files and IO
Modules and imports
Cabal projects
Dependencies
Testing with HUnit
Property testing with QuickCheck
Laziness and infinite lists
Strictness and space leaks
Folds
Monoids
Traversable
Monad transformers
Errors and exceptions
Concurrency
Parsing with Megaparsec
Capstone: a todo CLI
Hero roadmap: the whole course on one page

Search this site

Channel @aofeed Chat @aofeedchat

Contacts and cooperation:
I recommend our hosting beget.com
Write to info@aredel.com if you:
1. Want to write an article for our site or translate an article into your native language.
2. Want to place thematically relevant ads on the site.
3. Ads on my site pass maximum censorship. If you see an ad block unsuitable for school-age children, shocking or misleading - please contact us by e-mail
4. Found a mistake, inaccuracy, bug, etc. on the site. ... .......
5. Articles can be shared on social media by clicking a network icon: