How this book came to be: instead of an introduction

Feel free to skip this somewhat philosophical intro right to the Chapter 1

Lately, I’ve been spending quite a bit of time with Type Theory, lambda cube (e.g., implementing SystemF-omega-ish type library in coffeescript for the fun of finding out how things work as Dr. Feynman used to say), toy functional languages (Haskell is great, but what would a great functional language look like if it were designed today — with all that we’ve learned from state-of-the-art Haskell development in the last 20 years?), parsers, GUI libraries design and functional reactive programming.

Two thoughts persisted:

  • “I need to write another monad tutorial” — haha, got ya— “how do I teach functional programming to my kids?”  — so that it’s light, comprehensible, fun and conveys the beauty of the concepts involved,  —  and:
  • “we’ve been doing it all wrong”

Ok, the latter may be a gross exaggeration, but I need to drive the point across. As many unfortunate souls before me, I have gone down the painful but oh-so-typical road of coming from imperative OO background and trying to build bridges from the patterns learned there to a completely, absolutely different functional world.

The problem with this is, your brain works against you
(do read the classic “Thinking, Fast and Slow” by Dr. Kahneman if you haven’t yet — at the very least, it will help you detect and fight your own biases)

Our brain’s “System 1” works in patterns. It is efficient, extremely fast — much faster than the conscious “System 2”, which we are using when studying Category Theory, — it is in contrast subconscious, it deconstructs and shreds all the elephants you see in your life into basic shapes and curves and colors, which makes recognizing elephants a very easy task, until one day you glimpse upon a cloud like this —

it’s a cloud

— and your brain goes: “oh, look, it’s an elephant!”

Well, no, it’s a cloud.

And this is exactly the trap laid out for programmers trying to escape to the wonderful world of Haskell from the less elegant Java, C++, or that terrible-which-shall-not-be-named-but-ends-in-…avaScript backgrounds. The thought goes: C++ is a programming language, as is Haskell, so the concepts should be pretty similar, right? Isn’t it like Indian and African elephants: sure, one has bigger ears but aren’t they essentially the same?

No, they are not: one is an elephant and the other one is a cloud. You cannot reason about clouds using your elephant knowledge. You can ride an elephant, but attempting to ride a cloud would end really badly. Your brain constantly tries to find analogies between your previous experience and new knowledge — that’s how we learn, it is a good thing — but in this case the unfortunate fact that both Haskell and JavaScript are called “programming languages” is a disservice, as trying to find similar patterns in both leads to consequences only slightly less disastrous than trying to ride a cloud thinking it’s an elephant.

To master the power of Haskell, you need to set aside everything you know about imperative programming and build upon a totally different foundation. One of pure abstract math, starting from category theory, from set theory, from type theory, from Henri Poincare; you have to build Natural numbers with pen and paper starting with an empty set, construct a Ring on them, abstract away and discover Monoids, start appreciating the beauty of internal structure of types and categories manifested in polymorphic functions and laws on them, be amazed at how one abstraction can elegantly describe seemingly unrelated entities…

But who in the world has time for this?!

Well, exactly. This is one of the primary reasons there’s still a certain bias against Haskell among practitioners — a big part of Haskell community give impression of very smart monad-stacking-arrow-composing-scientist-magicians sitting in their ivory towers with too much time on their hands working out some abstract problems, while we need to code stuff that works even if it’s ugly.

Take heart, there’s hope! But before I outline a proposed (yet another) way out, let me illustrate the elephant vs cloud conundrum with a pretty typical “where is my for loop?!” situation.

Let’s say you are building a GUI library based on some low-level API and need to render lines of text on screen. You construct an array of textures where each corresponds to a new line of text and need to render each one under the other, incrementing an y coordinate, like so:

1 int y = 100;
2 int step = 40;
3 for (int i = 0; i < numOfTextures; i++) {
4   renderTexture (texture[i], y);
5   y += step;
6 }

Something you’ve done a thousand times in different situations. You switch to Haskell where you have a list of textures textures :: [Texture] and your System 1 starts screaming “where is my for loop?!” and then “how do I pass the state when iterating?” Should I use mutable variables, IORef, MVar, TVar ? I know I am supposed to map over lists, so should I use a State monad to increment y while mapping?

And only when you tell your System 1 to stop getting ideas from your imperative experience, consider abstractions, realize it is best to fold and traverse structures in the functional world, you come to something like:

1 foldM (iterate step) startingY textures
2 where iterate s y tex = renderTexture tex y >> (y + s)

… which gives you goosebumps after all the braces and semicolons in the c-land, but patterns have nothing in common: you iterate over arrays with mutable variables in one and you fold structures with computations in the other. Elephants and clouds.

So, how do we teach Haskell to kids or help adults master its’ power faster and more efficiently?

First, stop trying to build bridges from imperative world — it messes with people’s brains. In fact, explaining design patterns for program architecture on the real world problems and contrasting approaches with imperative world is actually very much needed and largely missing now — but this needs to be done only after a student has learned functional approach and small patterns from scratch. However, starting teaching Haskell in the bottom-up imperative way, with “Hello World” and calculator in ghci is in my strong opinion absolutely counter productive — it leads right into the elephants vs clouds trap and it takes much longer to start appreciating the power and beauty of Haskell.

We need to start from something close to the Type Theory, make people understand and fall in love with Types, their structure, their daily lives, their relations with each other; student has to become fluent in writing and understanding type level functions before she even thinks about writing “real” functions. It is actually a pretty traveled road as well — but only  if you have a reasonably strong math background.

Catch up on your Category Theory reading (Bartosz Milewski’s “Category Theory for Programmers” is out and it’s excellent), study Typeclassopedia, use amazing Stephen Diehl’s “What I Wish I Knew When Learning Haskell” as a reference, and get a feeling on how to structure real programs using monad transformer stacks, but whatever you do, under any circumstances, DO NOT read monad tutorials! Monads are actually very simple, it’s just another beautiful and powerful math abstraction, one among many, and you will confuse and break your brain with false analogies if you read the tutorials — study it in the context of Functor-Applicative-Monad hierarchy, so, again, Typeclassopedia.

Then, what was the point of all this? I am a very visual person when studying, and I’ve been thinking for some time now that math concepts underlying modern functional programming and type theory can be explained in a more accessible way using visuals, magic and various cute animal related analogies. Existing literature on the concepts mentioned above is often too technical, even for practicing programmers, let alone kids, even in their teens, and focuses on formal proofs a lot.

However, if we ease on trying to rigorously prove stuff and just illustrate and explain those same concepts, from lambda calculus in SystemFw (even the name is a mouthful, but the machinery is again extremely simple!) to types and their relations to category theory and arrows, in a top-down visual approach, this may help people build new patterns, completely unrelated to imperative programming, and then gradually move to more technical, more in-depth study while already becoming productive in writing elegant Haskell code for practical tasks. Something in the spirit of excellent “Learn you a Haskell” but building up upon math foundation of types and typeclass hierarchy vs “hello world” and ghci REPL.

Hence, the idea of “Magical Haskell” was born. In fact, it should probably go well hand in hand with “Learn you a Haskell” - with the latter providing for a lot of basic language foundation in much more detail, and “Magical Haskell” focusing on trying to create a system of typed functional patterns, typeclass hierarchy, and explaining abstract technical concepts in an accessible comprehensible way.