Closed davidchambers closed 6 years ago
I don't mind defining mapRight
as an alias for map
or bimap(identity, f)
, but I don't like the idea of trying to "type coerce" an Array into a pair. I know it's idiomatic to use it that way, but I wouldn't want it in this library as, to my mind, sanctuary-type-classes
should have no knowledge of Santuary's type checking capabilities.
I don't like the idea of trying to "type coerce" an Array into a pair -- @gabejohnson
There's no type coercion happening. I worry that you've misunderstood this:
mapRight
would be equivalent tomap
forEither a b
and various other types. ForPair a b
, though, [...]mapRight
would behave differently frommap
. -- @davidchambers
I want to make sure that you understand that this happens naturally - not because we are checking any types. What's being proposed are two simple things, of which neither sound wrong to me:
mapRight
, derived from bimap
.Together, this would allow me to map over an entire array with map
, and adjust just the right value of a binary array using mapRight
.
The problem might be that we are breaking a Fantasy Land law doing this:
If a data type provides a method which could be derived, its behaviour must be equivalent to that of the derivation
And map
can be derived from bimap
. So having a value ['a', 'b']
with two differing map implementations might be in violation.
So in other words
Is
mapRight
not a thing?
It is a thing: map
is mapRight
for all instances of Bifunctor.
The more I think about it, the less of a good idea this seems.
@Avaq [1, 2]
has two possible instances of Functor, one derivable from its instance of Bifunctor, and one that is not (this is no different from the two possible applicative instances of an array). Providing a mapRight
allows you to unambiguously access the Bifunctor derivable Functor instance's map
where there is ambiguity.
There are of course other ways to resolve the ambiguity, such as using type-reps (which is how the applicative ambiguity is resolved) or being able to reorder precedence of type classes in a local scope, but these are a little trickier than just adding an alias.
@Avaq I understand what's being proposed. I put "type coerce" in quotes because I didn't have a better term in mind at that moment. I should have said "give Array a Bifunctor instance".
I want to make sure that you understand that this happens naturally - not because we are checking any types. What's being proposed are two simple things, of which neither sound wrong to me:
- Adding a Bifunctor instance to all Arrays of length 2.
- Adding mapRight, derived from bimap.
I object 1 but not 2. I think it's going to be confusing in the long run to add a Bifunctor instance for arrays of any length and I suspect we'll end up deciding to remove it in the future.
What's stopping us from adding a Bifunctor instance for arrays of length 3?
instance Bifunctor (Array3 a) ...
@gabejohnson Yeah. I see your point now. It seems we agree.
sanctuary-type-classes
should have no knowledge of Santuary's type checking capabilities.
I agree. I was thinking that Array$prototype$bimap
would do the length check itself and throw if this.length !== 2
.
I think it's going to be confusing in the long run to add a Bifunctor instance for arrays of any length and I suspect we'll end up deciding to remove it in the future.
I appreciate your cautiousness. Let's leave this issue open while pushing to release sanctuary-pair. The ergonomics of the real Pair a b
type may prove to be excellent, in which case the value of treating two-element arrays as bifunctors would be greatly diminished. The existence of bimap
, mapLeft
, and map
mean many Pair a b
transformations can be performed without lambdas, diminishing the importance of an inherent advantage of arrays: the ability to write ([k, v]) => ...
.
The existence of bimap, mapLeft, and map mean many Pair a b transformations can be performed without lambdas, diminishing the importance of an inherent advantage of arrays: the ability to write ([k, v]) => ...
Additionally, Pair
implements the ECMAScript Iterable
protocol so
(([x, y]) => x + y)(Pair(1, 2)) // 3
We can have our π° and π΄ it too π
@masaeedu shared this snippet in the Gitter room:
After some discussion we agreed this code could be significantly nicer if
S.pairs
returned an array of honest-to-goodness pairs. One could then write:This is not possible because
['foo', true]
does not supportbimap
/mapLeft
. It could do, but a problem arises when one considersmap
. How shouldS.map (S.toUpper) (['foo', 'bar'])
evaluate? If one sees['foo', 'bar']
as a member ofArray String
, the result should be['FOO', 'BAR']
. If, on the other hand, one sees['foo', 'bar']
as a member ofPair String String
, the result should be['foo', 'BAR']
. (Treating['foo', true]
asPair String Boolean
while treating['foo', 'bar']
asArray String
is out of the question.)I'm reluctant to support
bimap
andmapLeft
while leavingmap
out in the cold. I would rather not treat two-element arrays specially at all, and have functions such asS.pairs
use the realPair a b
type soon to be released as sanctuary-pair.@masaeedu posed an intriguing question:
It certainly could be a thing. It's trivial to derive from
bimap
, as was the case withmapLeft
. We could provide the following four functions:mapRight
would be equivalent tomap
forEither a b
and various other types. ForPair a b
, though, orArray2 a b
as it will be known if sanctuary-js/sanctuary-def#182 is merged,mapRight
would behave differently frommap
:I'd still like to consider having
S.pairs
return a real pair rather than a two-element array, but improving the usefulness of values such as['foo', true]
may be a good idea regardless. What do you think?