DEV Community

Cover image for Building Expressive Monads in Javascript: Introduction

Building Expressive Monads in Javascript: Introduction

Rob Porter on June 07, 2019

The monad is a powerful design pattern that, when used correctly, can completely change how you think about handling values in Javascript (JS). Thi...
Collapse
 
eric_brisco profile image
Info Comment hidden by post author - thread only accessible via permalink
Eric Brisco

Happy to see your interest in Monad. However, there are numerous errors throughout this tutorial beginning from a wrong definition of Monad.

I hope you continue to study what a Monad is. In the interim, for the sake of other learners, this tutorial should be taken offline until it can be corrected.

Give me a shout and I'll provide what information and answers I can to help you fix this tutorial.

Collapse
 
rgeraldporter profile image
Info Comment hidden by post author - thread only accessible via permalink
Rob Porter • Edited

If you can find code not working correctly, please post it here. I would love to know what you have found wrong in the code if so.

It was stated at the beginning of the article that is more of an expressive, practical approach in JS, and not a lesson in category theory or mathematics.

I'm more or less following the principal of not overloading the reader with information that isn't required in order to make use of the pattern in day to day programming. This approach is used often in many forms of education, where certain things are glossed over in order to serve the broader goal of transferring knowledge. One doesn't learn how a car's engine works when learning to drive, just how to operate it, as an example. But if you want to be a car mechanic: yes, you learn more than how to accelerate and break to get to know a lot more and know that everything is not so simple.

Collapse
 
eric_brisco profile image
Eric Brisco

Explaining concepts clearly and simply is a laudable task. However, several parts, while perhaps being digestible, are factually wrong.

An example: emit is not part of monads. Also, emit and join are not the same thing.

If the goal is just to present some technique for writing JS programs then I have no qualms. If the technique is ascribed to monads, however, then I have to object.

Thread Thread
 
rgeraldporter profile image
Rob Porter

emit as I described, is a made up term. I borrowed it from CouchDB because I do find it far more expressive. join was also made-up when monads were adapted to Haskell, as a term to remove an abstraction layer. This is why I mention about expressivity in the article, to someone unfamiliar the term join (and Haskell, etc) doesn't make a lot of sense and it's just another weird thing to learn that I feel could be made easier. In my opinion as long as the functionality of a join exists, the name doesn't matter. But I do know others do not share that opinion and that is fine.

Like I say above, naming things is hard. Expressivity helps people immensely overcome barriers to using new techniques. Some monad libraries for JS use value for a join, but to me value is not being used as a verb, so I prefer emit. When teaching folks how to use it, many pause and ask for why it's called join, which interrupts the flow in learning just to satisfy some historical reason that has nothing to do with Javascript.

When I do write a monad I always make sure that join is there, and emit is just added as an alias. Same with map and fmap and so on. I always make sure the Monad Laws pass (I didn't even mention those here because that would be a whole other explanation). But for an "introduction" that can get someone doing something that is so different and almost counter to how JS works, I think a lot of the historical names and advanced conventions can be postponed for another day.

Thread Thread
 
eric_brisco profile image
Eric Brisco

I have no problems with the names you have chosen.

When I say emit is not the same as join, what I mean is that emit (as you have defined it) is not equivalent to join (as Haskell defines it — if you wish to use that as a point of reference).

Emit is in fact equivalent to extract, which is part of Comonad but not part of Monad. There is no way to do what emit does with a Monad.

You can define join from Monad, or join can be used in the definition of Monad — there are different equivalent ways to formulate Monad.

This is not a naming problem. This is a problem with the definition of Monad.

Thread Thread
 
rgeraldporter profile image
Rob Porter • Edited

Well, at this point I'd have to say you'll need to also take it up with various other existing monad implementations that have been created in Javascript. These are all from folks who know way more than me and could answer better your concerns.

It's done in Professor Frisby's guide here and in his videos:

mostly-adequate.gitbooks.io/mostly...

And in the Composing Software book (this is a part of it):

medium.com/javascript-scene/javasc...

(He also points out rightly that one can just omit join altogether and use a chained identity for this kind of thing. That might actually be easier from an educational perspective, I'm not sure.)

As does the monet.js monad library which aliases join to be like .chain(a => a) which might as well be () => x in the end, it's just a semantic difference.

And this last one on Maybe by James Sinclair is another, just using a class-style monad.

jrsinclair.com/articles/2016/marve...

Thread Thread
 
eric_brisco profile image
Eric Brisco

For Monad to make sense, types cannot be ignored. That is why join is being misunderstood.

I have not watched Professor Frisby's explanation so I have no comment there.

Eric Elliot misunderstands join in his article you linked. I'll try and get in touch.

monet.js does it right. Read carefully what the type of join is.

James Sinclair describes join accurately and then, following that, explains why emit cannot be defined for Maybe. I recommend rereading his work carefully.

Collapse
 
suddenlygiovanni profile image
Giovanni Ravalico • Edited

TS Identity interfaces

interface IdentityMonad<A> {
  /**
   * method that just returns the value contained within.
   */
  emit: () => A

  /**
   * method which is intended to chain various monads together
   */
  chain: <B>(f: (x: A) => B) => B
  /**
   * `map` it is the chain function with a built-in rewrapping of the resulting value into a
   * new Identity, which itself can be subject to map, chain, and emit on and on for as many
   * functions you'd like to apply to it.
   */
  map: <B>(f: (x: A) => B) => IdentityMonad<B>

  inspect: () => string
}

interface IdentityFactory {
  <A>(x: A): IdentityMonad<A>
}

Collapse
 
rgeraldporter profile image
Rob Porter

This is great! 👍

Collapse
 
aestheticsdata profile image
joe cool

@rgeraldporter Are you using the Monad pattern in all your codebases on an everyday basis ? For instance, have you replaced all of your try/catch block with some Monads ?
I'm an experienced dev, but I've never used it, I'm trying to understand this pattern, and your article is a fresh air among a lot of not very practical explanations on the web.
With javascript, an app can easily crash with a null/undefined error, so I'm a bit surprised that the Monad pattern is not more widespread if it's really a safe wrapper.

Collapse
 
artydev profile image
artydev • Edited

It is a radically another way of thinking, and changing minds is very very difficult.
It takes very long time to convince your colleagues in a team .
Once the brain is wired in some way, changing minds is like 'digging' and 'rewiring' new ways of thinking in this brain, and it can be a pain, especially if you have reached a certain age...(I am 61 years old :-))

Collapse
 
artydev profile image
artydev • Edited

Thanks for this introduction.
Regards

Collapse
 
potbunker profile image
potbunker

Nice way to ease into Monad! Appreciated.

Collapse
 
rgeraldporter profile image
Rob Porter

Thank you!

Collapse
 
seangwright profile image
Sean G. Wright

Great explanations. I liked how you started with Identity and slowly build up to Maybe.

Thanks!

Collapse
 
rgeraldporter profile image
Rob Porter

Thanks!

Collapse
 
aestheticsdata profile image
joe cool

instead of exporting the monads with an intermediate "of" construct, we could add the "of" method as a property of the monad, eg:

List.of = x => List(x)

Some comments have been hidden by the post's author - find out more