fantasyland / function-prototype-map

4 stars 0 forks source link

implementation #1

Open davidchambers opened 7 years ago

davidchambers commented 7 years ago

Start with the type of map as defined by the Functor type class:

map :: Functor f => f a ~> (a -> b) -> f b

Replace Functor f => f with Function x:

map :: Function x a ~> (a -> b) -> Function x b

Replace Function $1 $2 with ($1 -> $2):

map :: (x -> a) ~> (a -> b) -> (x -> b)

Rename type variables:

map :: (a -> b) ~> (b -> c) -> (a -> c)

Here's the implementation from sanctuary-type-classes:

//  Function$prototype$map :: (a -> b) ~> (b -> c) -> (a -> c)
var Function$prototype$map = function(f) {
  var functor = this;
  return function(x) { return f(functor(x)); };
};

We should add something similar to the readme:

//  Function#map :: (a -> b) ~> (b -> c) -> (a -> c)
Function.prototype.map = function(f) {
  var g = this;
  return function(x) { return f(g(x)); };
};

It's worth noting that this is different from the implementation in your tweet, @puffnfresh. Unless I'm mistaken your version does not have a type compatible with fantasy-land/map.

JAForbes commented 7 years ago

Would usage be something like?

const pythagoras = 
  ap([square]) // [9,16]
  .map(sum)  // 25
  .map(Math.sqrt) // 5

pythagoras([3,4]) //=> 5
davidchambers commented 7 years ago

I don't understand what's going on in your example, @JAForbes. Here's a straightforward example:

> Math.abs.map(Math.sqrt)(-64)
8

> Math.sqrt(Math.abs(-64))
8
davidchambers commented 7 years ago

Oh, I see it now. ap is a curried binary function. Nice!

JAForbes commented 7 years ago

I like the simplicity of your example @davidchambers. I think in the readme we'll need lots of simple examples that solve some concrete problems. If anyone has any ideas, please post away.

puffnfresh commented 7 years ago

@davidchambers my tweet was wrong, thank you!

safareli commented 7 years ago

If this is goint to be a proposal, I think we would need to also support this and multiple arguments:

Function.prototype.map = function(f) {
  var g = this;
  return function(...args) { return f(g.apply(this, args)); };
};
obj = {
  foo: 1,
  bar: function(a) {
    return this.foo + a
  }.map(Math.sqrt)
}

obj.bar(3) // 2
nadameu commented 7 years ago

@i-am-tom has written an excellent series of blog posts about Fantasy Land. In Functions as Functors he implements Function.prototype.map, Function.prototype.ap and Function.prototype.chain, and explains their usefulness through simple and practical examples.

i-am-tom commented 7 years ago

Funnily enough, @gabejohnson is pushing for Function.prototype.compose in fantasyland/ECMAScript-proposals#1, and I'm thinking more and more that these two should be unified.

Variadic arguments would be unlawful (if we're thinking about map as meaning, "what we can do with a functor"). Similarly, compose has the same problem. However, if we push for something like pipe (which isn't such a loaded term), all of these things can be derived more strictly from that base, while simultaneously not upsetting those outside of FP by imposing unary function restrictions.

Given the ten minutes of thought I've applied, this seems like a compromise that could be accepted by both parties. My preference for this is purely because it's going to be difficult to push anything functional on the larger JS audience without bastardising it, which would be a shame.

Thoughts?

JAForbes commented 7 years ago

However, if we push for something like pipe (which isn't such a loaded term), all of these things can be derived more strictly from that base, while simultaneously not upsetting those outside of FP by imposing unary function restrictions.

I like this approach. It allows us to be less concerned about functions being lawful, without harming chances of having lawful implementations in the distant future when the value of lawfulness has been proven out in the mainstream.

jedwards1211 commented 6 years ago

If this is a proposal for ECMAScript, you might want to speak the language: use Flow or TypeScript-like syntax for describing types instead of Haskell syntax.