Haskell Context of Reasoning

Fang Jin
The Startup
Published in
3 min readDec 3, 2020

--

How difficult is writing a for loop?

We start programming by learning how to perform a loop, such as the following example.

for (let i = 0; i < 6; i++) { print i; }

I don’t know if this bothers you, but looping isn’t pretty to look at. Not to mention the additional boilerplate as well as keeping track of the extra index. Moreover it breaks the flow of your reasoning. Mentally you have to take a break whenever you encounter a loop.

It is costly, for sure, we don’t want to approach problem in higher dimensions, we tend to flatten our thoughts so that we can stay in a linear one dimensional structure most of time thus the visualization of the data flow becomes effortless.

Binding

Let’s take one step back and see how Haskell approaches this type of reasoning. Below is what’s called list comprehension.

[i | i <- [0..5]]

What’s interesting is on the i <- side. You might think it’s assigning the list to i. But this is not true, it’s actually binding the context to i, so that i stands for the (possible) value inside the list, just like in the classical, Déjà vu?

Here comes another example for the nested loops. You can see writing multiple loops is just adding more <-.

[(i+j) | i <- [0..5], j <- [i..5]]

Weird as it looks like, you are writing the logic on the same line or next line, but not another block of code, or nested block of code. Pause here, just try it in other language for a second.

Interestingly, this doesn’t just work for list only. It was actually designed for any context, let it be array, map, set, or any type you can imagine, as long as it contains some value of interest. The syntax will be very similar for them,

[i | i <- Context]

I use context when I’m referring to array or any higher level structure for the sake of this article. The precise definition is more relating to the sub-classing list as a Monad.

Context

Does that mean we can avoid writing loop? Probably not, but maybe we should start thinking things as matter of contexts. We can quickly use the available context to solve the problem while preserving the main thread of reasoning. This help us attempt higher dimensional or more complex problems without detouring too much into a matrix of sub-problems.

This level of focus is brought by a language that is well prepared with this complexity. To be honest, researchers have been the main frontier of this domain. But let me provide with one more practical example, finding two numbers that sum up to be 2020.

>>> let nums = [1, 2, 45, 903, 2323, ...]
>>> [(a, b) | a <- nums, b <- nums, a + b == 2020]

Is the above easy enough to teach kids 6 years old to solve it? I’m not trying to be pushy, but the answer is a bit more positive here. Most importantly is this approach more intuitive comparing to the the technical side of programming? In the end who’s that fascinated about the detail of programming anyway.

--

--

Fang Jin
The Startup

#OpenToWork Front-end Engineer, book author of “Designing React Hooks the Right Way” sold at Amazon.