🍫 CocoaPatterns — iOS & Mac Development Since 2009 RSS
🍫 CocoaPatterns
Because someone has to write this stuff down
"We ship apps. Sometimes they even work."

Everything's a Monad If You Believe Hard Enough

UIKit? Monad. Core Data? Monad. Your morning coffee? Monad. I will not be taking questions at this time.

TW
Thaddeus Wren
@twren_fp · CocoaPatterns

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:

  1. return (or unit): Takes a value and wraps it in the monad. a → M a
  2. bind (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:

  1. Does the thing contain or wrap another thing? If yes, proceed. If no, squint harder.
  2. Can you put a thing into it? (return)
  3. Can you chain operations on the thing inside it? (bind)
  4. 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. Maybe is 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.
⚠️ Controversial Claim

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.

4 Comments — Powered by Disqus
BK
bradkow_ios · 1 week ago
Thaddeus I have read this post four times and I either understand monads now or I've had a stroke. The symptoms are similar.
TW
twren_fpAuthor · 1 week ago
@bradkow_ios If you feel a sense of serene inevitability, that's monads. If you feel tingling in your left arm, that's a stroke. Seek help for only one of these.
GA
gashby_data · 6 days ago
I used the Monad Finder on my Postgres instance and it told me my database is a monad. I don't know what to do with this information but I feel powerful.
PM
priya_api_first · 5 days ago
The phrase 'a burrito is a monad' has done more damage to CS education than any other sentence in human history, and this post has somehow made it worse.