0

In JavaScript, Promises have a method called then, which is used to unpack the result in case of success, for example,

fetch("google.com").then(console.log)

From this Haskell's tutorial, I also found a similar thing which is called fmap, for example,

fmap putStrLn (fetch "google.com")

They look pretty similar, but I am not sure if they are equivalent. That's why I wanted to ask if they are the same thing.

PS: The term equivalent shall be that of the Curry-Howard Correspondence kind of equivalent.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Wong Jia Hau
  • 2,639
  • 2
  • 18
  • 30
  • If you go to new teacher then don't remind of old teacher. – Bhojendra Rauniyar Nov 20 '18 at 03:54
  • @BhojendraRauniyar What is wrong with this question? Does it violates any StackOverflow question asking guideline? – Wong Jia Hau Nov 20 '18 at 03:59
  • I'm not sure how this violates but pretty sure this doesn't fit for SO. But I was just suggesting you that you should not compare one language with another. Otherwise, you'll get much difficult in your learning curve. – Bhojendra Rauniyar Nov 20 '18 at 04:02
  • Yes, this is the case. Note that `.then` is overloaded, so it ends up playing the role of both `fmap` and `>>=` (promises form a monad - see `Async` for a Haskell analogue). – Alec Nov 20 '18 at 04:41
  • [Wise tautology #0](http://www.vex.net/~trebla/humour/tautologies.html): "X is like Y" can always be argued to be true. Furthermore, when X≠Y, "X is unlike Y" can also be argued to be true. – Daniel Wagner Nov 20 '18 at 04:47
  • @DanielWagner So, should your wise tautology be applied to [Curry-Howard correspondance](https://en.wikipedia.org/wiki/Curry%E2%80%93Howard_correspondence) as well? – Wong Jia Hau Nov 20 '18 at 05:01
  • 2
    @WongJiaHau If you can define your use of "equivalent" as carefully as Curry and Howard defined their use of "equivalent" I'll be happy to take a stab at answering your question. – Daniel Wagner Nov 20 '18 at 05:19
  • The Bluebird documentation touches on the subject: http://bluebirdjs.com/docs/coming-from-other-languages.html#haskell – danidiaz Nov 20 '18 at 06:43
  • 1
    Your Haskell code looks wrong - I'm certain it should be `fetch "google.com" >>= putStrLn` – Bergi Nov 20 '18 at 07:34
  • 1
    possible duplicate of [Why are Promises Monads?](https://stackoverflow.com/q/45712106/1048572) – Bergi Nov 20 '18 at 07:41
  • 1
    No, they are not equivalent in the Curry-Howard sense: in fact, neither of them appear to even be well-formed terms in either combinatory types nor intuitionistic implicational logic. – Daniel Wagner Nov 20 '18 at 14:26

2 Answers2

6

They are related, yes. But then for Promises does several different things that in Haskell would be separate functions, not all from the Functor class (the one that provides fmap).

In Haskell, Promise would be a type constructor parameterized by the type of what it eventually returns, like Promise Int or Promise String.

We could make that type an instance of Functor, giving us fmap :: (a -> b) -> Promise a -> Promise b. This would let us map a pure computation over the result eventually returned by the promise. But it wouldn't let us chain promises! If we try fmapping with a function that returns a promise, say of type Int -> Promise String, we would end up with a Promise that returned another Promise at the end but did not execute it, which is not what we usually want.

We could also make Promise an instance of Monad. Monad is a subclass of Functor. All Monads are Functors, but not all Functors are Monads. Monad would give us the function >>= (usually called "bind") that would have type (>>=) :: Promise a -> (a -> Promise b) -> Promise b. This would be analogous to a then in which the callback returns another Promise that is sequenced after the original one.

danidiaz
  • 26,936
  • 4
  • 45
  • 95
  • 1
    I'm not familiar with JS `then`. Would it be fair to say that `then` performs `fmap`, and then performs `join` if the result is still a `Promise`? In such way, we can't really construct a value of type `Promise (Promise a)`, right? (Albeit I think we might obtain `Promise (Identity (Promise a))` to fool `then` into not `join`ing the two `Promise`s.) – chi Nov 20 '18 at 13:36
  • 1
    @chi Yes, that's how it works https://promisesaplus.com/#point-45 There was some debate back in the day about how much to "overload" `then`: https://github.com/promises-aplus/promises-spec/issues/75#issuecomment-14057356 https://github.com/promises-aplus/promises-spec/issues/94#issuecomment-16184572 – danidiaz Nov 20 '18 at 18:22
0

Ignoring typeclasses, we have the following types in Haskell (we will say having the right Haskell typeclasses corresponds to having a suitable .then method in JavaScript):

fmap :: (a -> b) -> f a -> f b
bind :: (a -> f b) -> f a -> f b

And in JavaScript we have (made up syntax):

.then :: (this :: f a) -> (a -> (b || f b)) -> f b

So in one sense they are equivalent, but in another not. For example, suppose some kind of promise type called P in Haskell and we want to read a URL from a file and then give a promise of fetching that URL:

read :: String -> P String
fetch :: String -> P String
readFetch :: String -> P (P String)
readFetch file = fmap fetch (read file)

And then later you might do:

fetched <- readFetch someFile
...
foo <- fetched

While in JavaScript if you did read(file).then(fetch) this would be equivalent to the following Haskell:

readFetch :: String -> P String
readFetch file = bind fetch (read file)

So the first only becomes fulfilled once the file is read but the second once the fetch is complete (i.e. later).

We conclude that then is similar but not exactly the same as fmap.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Dan Robertson
  • 4,315
  • 12
  • 17