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

handling of duplicate keys in Object$prototype$concat #48

Closed
davidchambers opened this issue Apr 20, 2017 · 9 comments
Closed

handling of duplicate keys in Object$prototype$concat #48

davidchambers opened this issue Apr 20, 2017 · 9 comments

Comments

@davidchambers
Copy link
Member

Sanctuary:

> Z.concat({x: 1, y: 1}, {y: 2, z: 2})
{x: 1, y: 2, z: 2}

Haskell:

> M.fromList [('x', 1), ('y', 1)] <> M.fromList [('y', 2), ('z', 2)]
fromList [('x', 1), ('y', 1), ('z', 2)]

We didn't discuss this behaviour in #2 as far as I can see; I think we diverged from Haskell's behaviour unintentionally.

/cc @puffnfresh

@safareli
Copy link
Member

safareli commented Apr 20, 2017

but it is more aligned with Object.assign

Object.assign({ a: 1 }, { a: 2 }) // { a: 2 }

@gabejohnson
Copy link
Member

It depends on whether you want

Z.concat({x: 1, y: 1}, {y: 2, z: 2}) === ({x: 1, y: 1})['fantasy-land/concat']({y: 2, z: 2})

or not.

It's somewhat related to the ordering disputes in sanctuary-js/sanctuary#239

@davidchambers
Copy link
Member Author

Would you like to chime in here, @JAForbes?

@safareli
Copy link
Member

here are couple snippets from index.js.

in this ones appropriate FL method is invoked on last argument (data last)

function reduce(f, x, foldable) {
  return Foldable.methods.reduce(foldable)(f, x);
}

function map(f, functor) {
    return Functor.methods.map(functor)(f);
}

function chain(f, chain_) {
  return Chain.methods.chain(chain_)(f);
}

In case of this ones it's hard to say that which one is data as both of them are dataish.

function concat(x, y) {
    return Semigroup.methods.concat(x)(y);
}

function equals(x, y) {
  ... Setoid.methods.equals(x)(y) ...
}

function alt(x, y) {
  return Alt.methods.alt(x)(y);
}

function of(typeRep, x) {
  return Applicative.methods.of(typeRep)(x);
}

So the issue is not in Object$prototype$concat, but in dispatching part of concat, equals and etc.
(Ii think it's fine as otherwise it's a bit unintuitive)

@davidchambers
Copy link
Member Author

@gabejohnson, I'm not at all concerned with the relationship between the order of arguments to a Z function and the order of arguments to the corresponding Fantasy Land method. The API provided by Z functions is relevant to everyone in the Sanctuary community, whereas the details of the Fantasy Land methods are only relevant to authors of algebraic data types.

So the issue is not in Object$prototype$concat, but in dispatching part of concat, equals and etc.

I don't think that's correct. See #49.

@safareli
Copy link
Member

In haskell mappend of Map is "left-biased" in JS we have similar function Object.assign (R.merge has similar semantics) which are right biased, so I think is better to stick with what we have as it's more intuitive to JS developer.

@JAForbes
Copy link
Member

I'd personally prefer the left argument for this function and several others (including S.alt ).

But I think that's because I often use merge to overwrite existing state. E.g pre-processing data before a server call, or update state in a Redux/Elm reducer/update fn.

But I can also see someone else wanting concat for objects to act like "ensure this object at least has these values". And that's a valid use case too.

And this is why I bring up S.alt, you can use that function to do similar things.

Currently S.alt isn't convenient for setting up a default value if both args are Just.

// overwrite if the 2nd arg is Just
var defaultVal = S.alt( S.Just('default value') )

defaultVal( S.Just('desired value') )
//=> Just('default value')
// :(

The other day in gitter I was saying the current argument order isn't conducive for point free. But on reflection, its not conducive for point free for my specific use case 😄 . Both styles are useful in specific contexts and inconvenient in others.

I'd rather the entire library is consistent. So unless we're going to be left biased for other functions, I think right biased is ( unfortunately for me ) the way to go.

But if we did switch to left biased, would that change the behavior of e.g. Array$prototype$concat ? In my mind concat order seems related to the matter of key collision preference, it would seem odd to have one order for values, and another order for conflict resolution.

@safareli
Copy link
Member

safareli commented Apr 23, 2017

You would need to use placeholder in Purescript too (or flip)

defaultVal = _ <|> (Just "bla")

@davidchambers
Copy link
Member Author

Let's stick with the current behaviour for the time being. As it's not clear that one approach is better than the other it's best to leave things as they are. We can revisit this issue if new information comes to light.

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

No branches or pull requests

4 participants