Why Monads Can’t Give You The Answer

Panu Viljamaa
5 min readApr 16, 2019

--

If you rely on the definition of monads you can’t use monads for anything — except for creating more monads.

Based on the definition of monads you know you can “put element-data into the monad” by calling a function referred to as “return()” (in Haskell). But do you know how to get the data out of it? No, the definition of monads says nothing about that. Yet monad-function bind() is able to do that, how else could it create new monads from existing ones. How is it all possible?

What is a monad? It is not a data-type you define. It is not a function you create. It is not an Interface. It is not a class. It is NOT A VALUE. It is a specific relationship between two functions expressed in terms of their the argument- and result-types.

In Haskell those two functions are called “bind()” and “return()” but those are just their ROLE-NAMES. The actual functions acting in those roles could be anything as long as some conditions are true about them which make them together form a specific monad. In this sense monads are truly a “pattern” in your software. “Monad” is a name given for a set of specific conditions between two functions expressed in terns of their argument- and result-types. It is very abstract.

No wonder there is much confusion about them. And Haskell using a function named “return” as a crucial part of its monads does not help much. In most common programming languages ‘return’ is the keyword you use to make a function return a result.

The tricky thing to understand about monads is that:

  1. “return()” creates “monads” out of what is called the “element-type” of the monad and “bind()” creates a new monad from an existing one. But …
  2. There is NO function for getting element-type-data “out of” the monad. Nothing is said about that. This is the part that confused me the most

How do you get data out of a monad? What can you do with them if you can’t get anything out of them? I hope I can answer that below.

It is confusing to say that bind() -function returns “a monad”. That may be said and I think that is a big part of the confusion. It is correct in the sense that we can say some data is a “Number” even though we know it is just a string of bits. What makes that a Number? Our interpretation.

The similarity of Numbers and Monads may be instrumental for understanding them easily.

You can not really “create monads” ever because a monad is a relation. Relation is an abstract thing, a statement about how two or more things relate to each other or don’t. Two ore more things are either in a given relation or not.

You can not create relations, you can only create things which relate. You can create two functions which together form a monad but you can not “create a monad”. The monad is them together and the monadic relationship between them, assuming they together follow the monadic laws. There might be many monads in your code you don’t know about.

It may be said that bind() and return() create and return monads, but better terminology is to say they return “monadic values” or “instances of a monad”. Think of a Monad as a class like a Number. You could say that ‘bind’ returns a monad in the sense that sum() returns a number. But in your Object-Oriented program whose methods return objects you would not typically say they return “classes”. You say they return “instances of classes”.

A good metaphor for monads is any built-in primitive data-type like Numbers or Strings — AND the laws that govern the results and arguments of the operations between them. A number is not a number unless you have a way to do arithmetic with it.

Note I’m not saying that Numbers and Strings are Monads but that they are somehow similar to them, they have some data, and some functions to operate on that, and some known laws that hold between the arguments and results of arithmetic calculations. You could say that Numbers are a category of things just like Monads are, and you would probably be right.

You can add, subtract, multiply, and divide numbers. But what you get back is always another number, or perhaps an error if you divide by zero. But, you might ask: What can I do with numbers if I can’t get anything out of them? I only get more numbers.

But numbers are represented by bits. A number is a number only in the eye of the beholder. I see bits. You see number! You don’’t need to know how to get stuff “out of numbers”— because you know numbers are things that follow Laws of Arithmetic.

When your program executes and operates on a “number” it is really only operating on a set of ones and zeroes, that’s all there is. The reason your program can calculate with numbers is that it INTERPRETS those ones and zeros as numeric values.

Computers don’t operate on numeric values, they operate on representations of numeric values. Similarly the monadic operations ‘return()’ and ‘bind()’ do not operate on monadic values. They operate on representations of monadic values. There is no such data-type as MonadicValue. Monadic values are represented by actual data-types, such as an Array of Numbers for instance. Is an array of numbers a monad? Is a string of ones and zeros a number?

The result of bind() or return() are “monads” only in the sense that a set of bits is a number, it is a number because there are functions that interpret those bits as number.

When bind() gets a monadic value as its argument it can assume the argument is something that was earlier produced by either itself or the return() -function that is part of the same monad, or by somebody that “speaks the same language”. Even if it wasn’t produced by bind() or ‘return()’ it will be INTERPRETED as it was.

To get “data out of a monad” you then just need to call bind() or return() and INTERPRET the results as what you know the bind() and return() mean by their results. Humpty Dumpty. If you read and understand the source-code of the bind- and return-function of the monad, you know what they mean.

So why a monadic value can’t tell you what is inside it? Because it IS the answer. It is 42. It is the data that needs to be interpreted as a monadic value.

--

--