define Array$prototype$bimap for two-element arrays
See original GitHub issue@masaeedu shared this snippet in the Gitter room:
export const capitalizeKeys = o => pipe([ keys, map(k => ({ [k.toUpperCase()]: o[k] })), reduce(concat)({}) ])(o);
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:
// capitalizeKeys :: StrMap a -> StrMap a
const capitalizeKeys = S.pipe ([S.pairs, S.map (S.mapLeft (S.toUpper)), S.fromPairs]);
This is not possible because ['foo', true]
does not support bimap
/mapLeft
. It could do, but a problem arises when one considers map
. How should S.map (S.toUpper) (['foo', 'bar'])
evaluate? If one sees ['foo', 'bar']
as a member of Array String
, the result should be ['FOO', 'BAR']
. If, on the other hand, one sees ['foo', 'bar']
as a member of Pair String String
, the result should be ['foo', 'BAR']
. (Treating ['foo', true]
as Pair String Boolean
while treating ['foo', 'bar']
as Array String
is out of the question.)
I’m reluctant to support bimap
and mapLeft
while leaving map
out in the cold. I would rather not treat two-element arrays specially at all, and have functions such as S.pairs
use the real Pair a b
type soon to be released as sanctuary-pair.
@masaeedu posed an intriguing question:
Is
mapRight
not a thing?
It certainly could be a thing. It’s trivial to derive from bimap
, as was the case with mapLeft
. We could provide the following four functions:
map :: Functor f => (a -> b) -> f a -> f b
bimap :: Bifunctor f => (a -> b) -> (c -> d) -> f a b -> f c d
mapLeft :: Bifunctor f => (a -> b) -> f a c -> f b c
mapRight :: Bifunctor f => (b -> c) -> f a b -> f a c
mapRight
would be equivalent to map
for Either a b
and various other types. For Pair a b
, though, or Array2 a b
as it will be known if sanctuary-js/sanctuary-def#182 is merged, mapRight
would behave differently from map
:
> S.map (S.toUpper) (['foo', 'bar'])
['FOO', 'BAR']
> S.mapRight (S.toUpper) (['foo', 'bar'])
['foo', 'BAR']
> S.mapRight (S.not) (['foo', true])
['foo', false]
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?
Issue Analytics
- State:
- Created 6 years ago
- Reactions:3
- Comments:10 (10 by maintainers)
Top GitHub Comments
Additionally,
Pair
implements the ECMAScriptIterable
protocol soWe can have our 🍰 and 🍴 it too 😄
I agree. I was thinking that
Array$prototype$bimap
would do the length check itself and throw ifthis.length !== 2
.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 ofbimap
,mapLeft
, andmap
mean manyPair a b
transformations can be performed without lambdas, diminishing the importance of an inherent advantage of arrays: the ability to write([k, v]) => ...
.