I've spent the last eighteen months studying category theory, Haskell, and the deep structure of computation. I've read Wadler. I've read Mac Lane. I've read a 340-page PDF titled "Category Theory for Programmers" that I printed at the office and my manager asked me to pay for the toner.
And I've arrived at a conclusion that will either revolutionize how you think about software or make you close this tab immediately:
Everything is a monad.
"A monad is just a monoid in the category of endofunctors. What's the problem?"
— A sentence that has ended more conversations than any other in computer science
What Is a Monad, Actually?
I'm not going to explain monads using burritos, boxes, or railway tracks. Those metaphors have failed. Instead, I'm going to explain monads using the only metaphor that has ever worked: monads.
A monad is a type M with two operations:
return(orunit): Takes a value and wraps it in the monad.a → M abind(or>>=): Takes a monadic value and a function that returns a monadic value, and chains them.M a → (a → M b) → M b
These must satisfy three laws (left identity, right identity, associativity) which I'm not going to explain because every time someone explains the monad laws, an engineer switches to Go.
The Monad Finder Algorithm
I have developed a rigorous, peer-reviewed (Brad read it) algorithm for determining whether something is a monad. It is as follows:
- Does the thing contain or wrap another thing? If yes, proceed. If no, squint harder.
- Can you put a thing into it? (
return) - Can you chain operations on the thing inside it? (
bind) - If steps 2 and 3 feel like a stretch, revisit step 1 and squint harder.
Let's apply this to the world around us.
UIKit: A Monad
UIViewController wraps a view. You can put content into it (return). You can chain transitions — push, present, dismiss — each producing a new view controller context (bind). UINavigationController is literally a list monad. It's a stack of monadic values. I cannot believe no one has published this.
-- UINavigationController as a monad pushViewController :: ViewController a -> (a -> ViewController b) -> ViewController b pushViewController vc f = UINavigationController.push (f (vc.result)) -- I have not verified that this type-checks. It feels right.
Core Data: A Monad
NSManagedObjectContext wraps a set of managed objects. You insert objects into it (return). You perform fetches and transforms that produce new contexts or objects (bind). The fact that it crashes 40% of the time on background threads is unrelated to its monadic properties, although I would argue that NSManagedObjectContext is a monad in the category of things that will ruin your weekend.
Things That Are Monads
Using the Monad Finder algorithm, I have classified the following:
- Optional / nil: Monad. (This one's actually real.
Maybeis the canonical example.) - NSArray: Monad. (Also actually real. List monad.)
- UITableView: Monad. Wraps cells. You bind data to cells via
cellForRowAtIndexPath:. Each cell can produce an action that generates a new table state. - A Git repository: Monad. Commits wrap diffs. Merge is bind. Rebase is... a different bind. An angrier bind.
- A Slack channel: Monad. Messages wrap text. Threads are bind. @here is a side effect, which monads handle gracefully.
- Coffee: Monad. The mug wraps the coffee. Drinking is bind (transforms coffee into alertness). The monad laws hold until your third cup, at which point associativity breaks down and you get the shakes.
- A meeting: Monad. Wraps an agenda. Each agenda item produces an action that generates the next meeting. Meetings are an infinite monad. This is why they never end.
My advisor (I don't have an advisor; Brad sometimes reads my drafts) has objected to several of these classifications on the grounds that "not everything is a monad, Thaddeus, and you need to stop emailing the Haskell mailing list about coffee." I stand by my work.
Practical Applications
I have refactored our iOS app to be fully monadic. Every method returns a monadic value. Every operation is chained with bind. The codebase is now 60% type signatures and 40% actual logic. Compile time has increased from 12 seconds to 8 minutes. But the code is beautiful. It's the most beautiful code no one on my team can read.
My pull request has been open for six weeks. The only review comment is from Brad: "What language is this?" It's Objective-C, Brad. It's always been Objective-C. It just looks like Haskell now. You're welcome.
Conclusion
The monad is not a burrito. The monad is not a box. The monad is not a railway track. The monad is everything. Once you see it, you cannot unsee it. You will walk through the world noticing monads in sandwiches, traffic patterns, and your relationships. Your relationships are monads. The bind operation is communication. The side effects are arguments.
I have never been happier or more alone.