Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

consider not using then #2

Closed
Raynos opened this issue Apr 12, 2013 · 85 comments
Closed

consider not using then #2

Raynos opened this issue Apr 12, 2013 · 85 comments

Comments

@Raynos
Copy link
Contributor

Raynos commented Apr 12, 2013

Promises are not and probably will never be monads.

So consider using something not taken by the promise people to avoid confusion

@kennknowles
Copy link
Contributor

Actually promises do form a monad. More accurate to say that the Promises/A+ standard does not expose the monad underlying promises. Still a good reason to choose a different name. I've used the less pithy "andThen" a few times...

@Raynos
Copy link
Contributor Author

Raynos commented Apr 12, 2013

Promises/A+ is not a valid monad.

@Twisol
Copy link

Twisol commented Apr 12, 2013

There is some evidence that, while Promises/A+ implementations aren't directly monads, you can readily wrap them to fit the Monad specification.

I'd also rather keep using then, because it describes the operation in an approachable way.

@puffnfresh
Copy link
Member

Their then implementation is compliant!

They don't have constructor.of just yet - but they're still talking to me about that. There's still hope it could be a full monad!

@Raynos
Copy link
Contributor Author

Raynos commented Apr 12, 2013

@pufuwozu var x = promise.then(function (x) { return Id(x) })

x is Promise<x> not Promise<Id(x)>. The assimilation of Thenable's ruins monad compliance and breaks the monad laws.

@Twisol
Copy link

Twisol commented Apr 12, 2013

@Raynos: There's only so much you can do in a language where essentially every function is partial, and multiple implementations of the same interface exist. Promises/A+ is a best-faith effort to make sense of the problem.

@puffnfresh
Copy link
Member

@Raynos that's not a valid use of then according to the Fantasy Land spec. It's specifically undefined. Anything can happen :)

I blame Promises/A+ - definitely, not Fantasy Land.

@Raynos
Copy link
Contributor Author

Raynos commented Apr 12, 2013

@pufuwozu in that case the problem is that then is not a Functor ?

So the issue is that Promises/A+ will probably not implement of(Id(x)) to return Promise<Id(x)> and instead return Promise<x>.

Ok there is still hope!

@puffnfresh
Copy link
Member

@Raynos yes, then in Promise Land falls back to something Functor-like which is completely broken.

I really hope Promise Land doesn't implement of like that, it'd also be very broken.

@Gozala
Copy link

Gozala commented Apr 12, 2013

As I commented in the famous thread:
promises-aplus/promises-spec#94 (comment)

I also think it would be a better idea cal this different than then. That would in fact make compatibility with promises easier. In fact I'd embraced upcoming private symbols and would just use names like:

var flatMap = "flat-map@fantasy-land"
var point = "point@fantasy-land"

function fmap(m, f) {
  return m[flatMap](f)

}

That way all the built-ins and promises can be easily adapted and made compatible. And if promise.then can desugar to several operations, argument can be made to mandate implementation of flatMap for promises keeping then around just for legacy.

@Gozala
Copy link

Gozala commented Apr 12, 2013

BTW the whole point of my method library was to avoid defining specific named methods, instead define API in form of functions and then adapt / provide implementations for arbitrary data types you'de be dealing with.

@raimohanska
Copy link
Contributor

I'm also not sure whether it's a good idea to use the name then as it is at least somewhat in conflict with Promises. On the other hand, using the same name might prove a good choice in practise, as it "works in most cases" which is often considererd good enough in Javascript.

I implemented the Fantasy spec in Bacon.js fantasy-land branch. Now you can wrap a Promise into an EventStream or a Property and have a Fantasy Land Monad/Functor:

Bacon.fromPromise(promise).toProperty()

I prefer Property because it's a stateful thing that "remembers" the latest value. So it doesn't matter whether you subscribe after or before the promise is resolved.

This (promise wrapping) is actually something we've been doing with Bacon.js for a long time, especially with JQuery ajax, so all I had to add was Fantasy compliant synonyms.

@puffnfresh
Copy link
Member

To summarise the state of then and promises:

  • I want Promises/A+ to be Fantasy Land compatible without a wrapper.
  • Promises/A+ implements a then that is compatible Fantasy Land
  • Promises/A+ haven't ruled out implementing constructor.of
  • Promises/A+ expects nothing other than promises to implement a then method

Some people think the behaviour of then when given something that returns a Fantasy Land monad is a useful behaviour. Some think it's buggy (including myself).

So Promises/A+ might become monadic but people might experience bugs in Promises/A+ if they pass Fantasy Land compatible values.

But @Gozala pointed out that we can use a different name and fallback to then in the case of promises:

function flatMap(p, f) {
  return (p.flatMap || p.then)(f);
}

What does everyone think of this solution? Is flatMap a fair name?

@raimohanska that's extremely awesome - hopefully we'll get this settled soon and we figure out a then name. Thanks!

@raganwald
Copy link

A long time ago in a company far, far away, there was a young engineer given a herculean task within an impossible deadline. He created LiveScript. One of the decisions he made was to make functions first-class values rather than have them be "something else" like the other popular languages of the day. Another was to use prototypical inheritance rather than classical inheritance, like the other popular languages of the day.

It would take years for the programming community to embrace the power of functions as first-class values in his language. Most people agree that Crockford got the ball rolling, followed by Oliver Steele and you can trace a direct line down to Jeremy Ashkenas and Underscore from there. Today, it is unthinkable to imagine a JavaScript without functions that can return functions or apply functions.

Conversely, prototypical inheritance hasn't reached a tipping point. The vast majority of programmers simply emulate classical inheritance and do not exploit its power in any way.

What does this history tell me about promises?

I think that promises-that-are-monads are in the same category as these two ideas I cited. If we embrace the idea of promises being first-class monads, we will likely have a lot of "meh" for a year or maybe three. Then someone will write a library or give a talk and the light will go on. It is had to imagine what wonderful thing will be created when that happens.

Did Brendan predict what people would build? No, he merely designed something that had a good feature and history rolled forward. I do not criticize promises-that-are-monads because it is hard to predict what good things they will enable. Plant the seed, and we will see what fruit its tree bears.

So, obviously, I am in favour.

Now, I do not wish to naysay those who argue against it. Thus, prototypical inheritance. It could be that everybody just uses it to emulate the thing we already have and never grow beyond it. It could be that it is just some weird thing that causes people to write books about its "warts and confusing features."

I don't know. Given the history of these two things--first-class functions and prototypical inheritance--it's fair to say that we don't know will happen if we introduce this idea. It could ignite like first-class functions. It could fizzle like prototypical inheritance. In 1996, who could predict which idea would grow and which would lay fallow?

But I do think this idea is the kind of elegant thing that makes new things possible. And I do know what will happen if we don't embrace this idea: We absolutely won't have new, powerful things.

I think the potential benefit outweighs the immediate "unpragmatism," and I think it is very JavaScript-y to do so. Much of the deep love people have for JavaScript is the way it is a powerful language made out of simple ideas.

That's because things compose and combine in elegant ways. So let's embrace that and find a way to make promises-that-are-monads happen.

JM2C. Thank you for your time reading my thoughts.

@santoshrajan
Copy link

I tend to agree @raganwald. I think @pufuwozu is onto something. The idea then should carry only one argument makes sense if you think of the continuation monad.

@runarorama
Copy link

Popular names for then:

  • bind
  • >>=
  • =<<
  • flatMap
  • concatMap
  • SelectMany
  • gosub
  • substitute
  • expand

@divarvel
Copy link

The java8 ML came up with interesting names as well

  • multiMap
  • explode

@runarorama
Copy link

I somewhat dislike flatMap and its ilk because it's biased toward tuple-like monads rather than function-like monads.

@puffnfresh
Copy link
Member

bind means something to JavaScript.

Is there anything that is partially monadic (like promises) that use something other than then?

@santoshrajan
Copy link

How about mThen

@divarvel
Copy link

In the same fashion: mBind

@natefaubion
Copy link

There's next. It's about as descriptive as then and the same number of letters, so little clutter.

@divarvel
Copy link

+1 with Runar on flatMap: gives a bad intuition to newcomers

@joseanpg
Copy link

I propose blend

@fogus
Copy link

fogus commented Apr 12, 2013

Some off the top of my head:

  • next
  • also
  • more

Other possibilities found in the thesaurus.

@pk11
Copy link

pk11 commented Apr 12, 2013

+1 for next

@divarvel
Copy link

+1 for next

@jackcviers
Copy link

My proposals:

m for Monad

also for also make Monad

over put a monad over this

wrap wrap in a monad.

@Gozala
Copy link

Gozala commented Apr 12, 2013

Please don't use next this name is already overloaded, also ES6 iterators will have it.
In reducers library I used term expand for that, although there it's a function not a method.

I know I'm repeating myself, but it would be a lot better to avoid mistakes that promise land made and
use unique names monad[expand] to avoid any collisions. Once private symbols are available expand
variable can become private symbol instead of being unique string.

@fogus
Copy link

fogus commented Apr 12, 2013

@Gozala Good point about iterators.

@joseanpg
Copy link

@pufuwozu since it seems that we need a verb: unicornize :D

@kennknowles
Copy link
Contributor

Also consider the confusion when someone tries to use the reverse state monad with then and next.

@puffnfresh
Copy link
Member

Seems like the next in like is chain - would this break anything? Is it already used as a monadic bind somewhere?

@puffnfresh
Copy link
Member

There were also some votes for expand.

@Gozala
Copy link

Gozala commented Apr 12, 2013

Why not monad[">>="](f) very unlikely to collide with anything, and users can alias with whatever their name preference is.

@Twisol
Copy link

Twisol commented Apr 12, 2013

Hmmm.

result = m [">>="] (function(x) {
    return x.constructor.of(x * 42);
  }) [">>="] (function (x) {
    return x.constructor.of(x / 2);
  });

It's certainly interesting. I think it's a bit too unusual to be accepted en masse though.

Maybe the specification could use these symbolic names, and individual libraries could alias them as desired. If someone wants to target monads in general, they can use the symbolic names.

@Gozala
Copy link

Gozala commented Apr 12, 2013

@Twisol I don't expect that you'll write that, but rather this instead:

function flatMap(f, m) { return  m[">>="](f) }

result = flatMap(function (x) {
    return x.constructor.of(x / 2);
  }, flatMap(function(x) {
    return x.constructor.of(x * 42);
  }, m);

As of chaining there are multitude of libraries that just do that.

@Twisol
Copy link

Twisol commented Apr 12, 2013

@Gozala: Yes, I agree, but I had to see how closely it mirrored Haskell. 😉 Like I said, most libraries would alias >>= and provide something a bit less esoteric.

I'm intrigued, but I think I still prefer chain. 😆

@Raynos
Copy link
Contributor Author

Raynos commented Apr 12, 2013

>>= is unreadable. For the love of god no.

@jedws
Copy link

jedws commented Apr 12, 2013

While flatMap does have some drawbacks, it does have some attractive values:

  • it nicely expresses the combination of a map of a M[A] via an A -> M[B] into a nested M[M[B]] followed by a flatten back down into a M[B]*
  • it is highly unlikely to conflict with much else
  • it is already in use elsewhere (Java8 and Scala), so has some familiarity value

* with apologies for the pseudo-scala syntax

@Gozala
Copy link

Gozala commented Apr 12, 2013

What I'm trying to say is it's not possible to make everyone happy with naming and I don't think it should be goal to come up with perfect name. I'd rather prefer robust name (that won't collide with other names) and then each of us can decide how we call it at home. I don't really care about name to be honest I just hope it won't collide with promises then or iterators / generators next.

@puffnfresh
Copy link
Member

@jedws I don't mind flatMap but seems like it has been voted down so much it sits around 0 votes 😯

@Raynos
Copy link
Contributor Author

Raynos commented Apr 12, 2013

+1 flatMap

@Twisol
Copy link

Twisol commented Apr 12, 2013

I'm not a fan of flatMap. I don't have any experience with Scala, but the name feels like it describes an implementation detail, rather than something describing a semantic action. I'd love to see some examples where the name fits better than chain though!

@kennknowles
Copy link
Contributor

thereupon
therewith
into
inject

I like adjectives better than verbs, actually.

@Twisol
Copy link

Twisol commented Apr 13, 2013

None of those are adjectives, actually. Adverb, adverb, preposition, verb!

@hughfdjackson
Copy link

I'm not a fan of flatMap. I don't have any experience with Scala, but the name feels like it describes an implementation detail, rather than something describing a semantic action. I'd love to see some examples where the name fits better than chain though!

+1 . Monads have a reputation for being hard to understand; and I believe this is mostly because the language is so opaque. Approachable API would probably have a big impact on how much the abstraction gets used.

@Raynos
Copy link
Contributor Author

Raynos commented Apr 13, 2013

can we call it .lulz()

@puffnfresh
Copy link
Member

@hughfdjackson abstract algebra has abstract names. I think it's impossible to find a single name to convey what the operation does in every context that it operates.

@natefaubion
Copy link

To throw another name out there: link. It's short. As a noun it's a segment in a chain. As a verb it's synonymous with bind.

Otherwise +1 flatMap as it has precedent and no one uses it.

@Twisol
Copy link

Twisol commented Apr 13, 2013

On a related note, we'll probably want a way to duck-test these types. There will always be the possibility for false positives, but it's valuable to have a specific mechanism to do so.

While the [">>="] name is really really ugly to actually use, it does provide a pretty reliable way to duck-test monads. Perhaps we could have two names for these functions: the canonical, symbolic name, and the expressive, semantic name.

@rtfeldman
Copy link

+1 for chain - intuitive enough, and only place I can remember seeing that method name used in a library is http://underscorejs.org/#chain

@joneshf
Copy link
Member

joneshf commented Apr 13, 2013

@joseanpg the word you were looking for was cornify

@junosuarez
Copy link

+1 chain. As @rtfeldman says, the underscore / lodash api is the only place that comes to mind for its usage (although as of 0.9.x, lodash has switched to using _() instead.) In these apis, chain has of semantics, just to add to the confusion :)

... barring that, +1 for @Raynos' .lulz()

@johanatan
Copy link

+1 for >>= and flatMap. elm uses these names and its goal is apparently to be an 'approachable Haskell' for people who would never think of touching the real thing.

@hughfdjackson
Copy link

@johanatan : A goal in which I haven't yet seen it succeeding - whereas promises have succeeded in providing a (quasi-) monadic interface with great success. >>= isn't a natural fit for javascript as a language OR an audience, and flatMap isn't a natural fit for the audience, imo.

+1 chain or link; so far, seem to be the best.

@puffnfresh
Copy link
Member

Thanks everyone for their input, chain came up as the winner. flatMap was a fairly close second.

I better factored the monad hierarchy and changed the name in e37674b.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests