Comment on What programming languages aren't too criticized here?

<- View Parent
angryzor@programming.dev ⁨1⁩ ⁨year⁩ ago

The problem is people constantly try to explain it using some kind of real world comparison to make it easier to visualize (“it’s a value in a context”, “it encodes side effects”, “it’s just flatmap”, “it’s a burrito”), when all it really is is an abstraction. A very, very general abstraction that still turns out to be very useful, which is why we gave it the cryptic name “monad” because it’s difficult to find a name for it that can be linked to something concrete simply because of how abstract it is. It really is just an interface with 2 key functions: (for a monad M)

- wrap: (x: T) => M // wraps a value
- bind: (f: (y: T) => M<u>, x: M) => M<u> // unwraps the value in x, passes it to f which should wrap that value again somehow, and returns what f returns

Anything that you can possibly find a set functions for that fit this interface and adheres to the rules described by someone else in this thread is a monad. And it’s useful because, just like any other abstraction, if you identify that this pattern can apply to your type M and you implement the interface, then suddenly a ton of operations that work for any monad will also work for your type. One example is the coroutine transformation (async/await) that is an extremely popular solution to the Node.JS “callback hell” problem that used to exist, and which we call do-notation in Haskell:

// instead of
const getPostAuthorName = foo => getPost(foo).then(post => getUser(post.authorId)).then(user => user.username)

// you can do this
const getPostAuthorName = async foo => {
  const post = await getPost(foo)
  const user = await getUser(post.authorId)
  return user.username
}

This is a transformation you can actually do with any monad. In this case Promise.resolve is an implementation of wrap, and then is an implementation of bind (more or less, it slightly degenerate due to accepting unwrapped return values from f). Sadly it was not implemented generally in JS and they only implemented the transform specifically for Promises. You may have noticed that generators with “yield” syntax are very similar to async/await. That’s because it’s the exact same transformation for another specific monad, namely generators. It’s sad because many people say they hate monads because they’re complex, but then heap praise on Promises and async/await which is just one limited implementation of a monad. List comprehensions are another common implementation where this transform is useful:

// instead of
const results = []
for (const x of xs) {
  for (const y of ys) {
    results.push({ x, y })
  }
}

// you could have
const results = do {
  const x = yield xs
  const y = yield ys
  return wrap({ x, y })
}

Another (slightly broken) implementation of monads and the coroutine transform people use without knowing it is “hooks” in the React framework (though they refuse to admit it in order to not confuse beginners).</u></u>

source
Sort:hotnewtop