0

Can anyone solve the challenge below (i.e. mapping over dataBad) using monads or similar FP implementation (NB caveat, can this be done in a way that would be familiar to Javascript developers)?


  const dataGood = [ { a: { b: 1 } }, { a: { b: 2 } }, { a: { b: 3 } } ]
  const dataBad = [ { a: { b: 1 } }, { a: { b: 2 } }, { b: { c: 3 } } ]

  // returns array
  return dataGood
    .map(obj => obj.a)     // [ { b: 1 }, { b: 2 }, { b: 3 } ]
    .map(obj => obj.b + 1) // [ 2, 3, 4 ]

  // breaks application
  return dataBad
    .map(obj => obj.a)     // [ { b: 1 }, { b: 2 }, undefined ]
    .map(obj => obj.b + 1) // TypeError: Cannot read property 'b' of undefined

POSSIBLE ANSWER: If Promise's are essentially monads, then wouldn't this be the most simple / javascript-esque monad implementation?

  const Maybe = val => new Promise(resolve => resolve(val))

  const dataGood = [ { a: { b: 1 } }, { a: { b: 2 } }, { a: { b: 3 } } ]
  const dataBad = [ { a: { b: 1 } }, { a: { b: 2 } }, { b: { c: 3 } } ]

  // returns null
  return await Maybe(dataBad)
    .then(val => val.map(obj => obj.a) )     // [ { b: 1 }, { b: 2 }, undefined ]
    .then(val => val.map(obj => obj.b + 1) ) // TypeError: Cannot read property 'b' of undefined
    .catch(() => null)
Ed Williams
  • 2,447
  • 3
  • 15
  • 21
  • 1.0001 is essentially 1 - while such a statement makes sense on a Sunday market it doesn't make sense in math and FP. From a FP POV a promise is a lawless abstraction, which like a pretty likeable guy :D –  Dec 21 '19 at 13:03
  • The function instance of monads is rather simple: `bind = f => g => x => g(f(x)) (x)`. Along with function composition it forms a monad. The identity monad is even simpler but hard to grasp because it does nothing useful than conforming to the monad laws. –  Dec 21 '19 at 13:13
  • @bob The simplest monad would be the free monad. [What are free monads?](https://stackoverflow.com/q/13352205/783743) – Aadit M Shah Dec 22 '19 at 08:35
  • Thanks for the comments guys. I posted this (rather general) question as it seems there are n number of libraries out there that provide monads in JS, but the docs always quickly disappear into category theory, whereas I was looking for something _very_ simple / useful - something that would solve the above example in the most natural javascript way possible. This seems to me to be Promises - but perhaps the hunt continues :) – Ed Williams Dec 22 '19 at 12:00
  • 2
    No, promises make a horrible monad, and also they force asynchrony where you don't want it. Don't do that. What you really want to use is the `Array` monad, with `dataBad.flatMap(obj => "a" in obj ? [obj.a] : [])`. Altough in this particular case, it's better (and simpler) to use the array-specific `filter` method, like `dataBad.filter(obj => "a" in obj).map(obj => obj.a.b + 1)`. – Bergi Dec 22 '19 at 15:52
  • 1
    This sounds like an [XY problem](http://xyproblem.info/). What are you actually trying to do? – Aadit M Shah Dec 23 '19 at 05:46

0 Answers0