This seems like the most relevant thing: ramda/ramda#1809

@JAForbes: mapping over a Map/WeakMap looks reasonable to me. Mapping over a Set scares me a bit. In some very real, if hard to formalize, manner, an important part of **shape** of the functor. But what would be the result of mapping

`map`

is that it retains the `square`

over the five-element set `{-2, -1, 0, 1, 2}`

?
@CrossEye can you explain a bit more? I'd have thought

`{4, 1, 0}`

would be a reasonable result?
(is it that there are fewer items in the resulting Set?)

@CrossEye Oddly enough in Scala you get a set of three elements:

```
val foo = Set[Double](-2, -1, 0, 1, 2)
foo.map(Math.pow(_, 2)) // => Set(0.0, 1.0, 4.0)
```

Surprised me, but now I'm curious to check with my Scala guys and hear about that

Hello

Greetings and salutations.

I want to get the most frequent value in a list, I'm pretty close but I'm missing the last bit :D

What are you trying?

```
R.pipe(
R.countBy(R.identity),
R.toPairs,
R.reduce(R.maxBy(R.last), 0)
)
```

it's good until the last function

It returns 0

:/

What's your input?

I have this one for example :

```
[ [ 'foo', 1 ],
[ 'bar', 1 ],
[ 'baz', 2 ] ]
```

outputed if I stop at R.toPairs

I just follow the example here : http://ramdajs.com/docs/#maxBy

seems right to me to use R.maxBy(R.last) for a list of pairs

then I should use R.head to get the initial value

oh :o :o :o

`R.reduce(R.maxBy(R.last), ['', 0])`

worked !

I was comparing 0 to a pair

xD

There ya go.

You're faster than me.

well no, I was comparing the count in the pair with R.last(0) :D

Thanks anyway @manchicken ^^

@CrossEye Looks like Haskell has the same behavior: https://downloads.haskell.org/~ghc/6.4.1/docs/html/libraries/base/Data-Set.html

"It's worth noting that the size of the result may be smaller if, for some (x,y), x /= y && f x == f y"

out of curiosity Immutable's Set does the same: it has a map method and returns a smaller Set

So, proof by prior art? :-)

@nateabele Well, as one of my "Scala guys" just reminded me, strictly speaking "as long as the functor returns a Set of values, and as long as the arrow is pure, then the functor is not breaking any rules"

That's kinda what I was thinking.

Length isn't strictly part of the 'shape'.

He also made me notice that in Scala Set and Lists aren't functors and that he thinks that "the scalaz representation of a functor is more natural, because it represents functors as type classes"

I'm quoting because it's out of my territory, actually

Hello, how to make function in Ramda that do equivalent operation:

(fn, [x, y, ...]) => fn(x)(y)...

(fn, [x, y, ...]) => fn(x)(y)...

Hmmm,

`converge()`

with `call()`

, I guess?
Cool, a thought about simple reduce

I*

Wait... I misread that. Yeah, reduce would work.

@nateabele thank you :)

@nateabele Exactly, length or ordering or else aren't part of the shape

I would have considered the length to be part of the shape to tell the truth, but now I'm reconsidering

@nateabele it turned out to be pretty simple:

const reduceCallable = R.reduce((acc, next) => acc(next));

const reduceCallable = R.reduce((acc, next) => acc(next));

Cool.

@ascartabelli I see it as, Arrays have length, and Sets have uniqueness, as their defining "container" semantics

I did wonder about ordering of Sets though

Yeah, I thought sets were ordered.

https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Set talks about insertion order

so I suppose you map over the contents in insertion order, and don't allow any duplicates to be inserted in the return Set (as opposed to removing the existing item and inserting the duplicate)

What are the downsides of memoizing a composition other than additional memory allocation? ie:

`compose(pluck('value'), memoize)`

What about other shapes? If you

`map`

over a tree, does the return tree have to have the same number of nodes? a graph?
@bgvianyc I don't think that does what you intend

`compose(g, f)(x) == g(f(x))`

@kwijibo does it need to be

`memoize(compose(map(crazystuff), pluck('value'))`

?
so

`compose(pluck('value'), memoize)`

is `pluck('value')(memoize(x))`

(ie, memoizing your value, not your function)

got it, so my question actually applies to the second example I gave.

@bgvianyc yes;

`memoize`

is a decorator
How does when decide when it makes sense to decorate with memoize?

when the size of the input set is small and computing the results is slow.

@bgvianyc I think like you said, memory concerns can guide you here. Think about what your function is doing;

are the results permanently cacheable?

will the function be called with the same arguments a lot?

will the results be more expensive to compute than to cache?

are the results permanently cacheable?

will the function be called with the same arguments a lot?

will the results be more expensive to compute than to cache?

My feeling is that relatively few functions will be worth caching in typical browser-side javascript

you can also 'temporarily' memoize by having an unmemoized version and then memoizing as a utility inside another function if you know that function will repeat the same work a lot (dynamic programming algorithms)

so each time your algorithm runs it gets a fresh memoized version

this can partially ameliorate memory usage concerns

This is good food for thought.

I'm no perf expert, but I'd probably start from a position of looking at some performance profiling to decide what, if anything, to memoize

right

rather than memoize functions as I write them

It's an interesting idea though; what if the default was for functions to be memoized, and you had specifically unmemoize the impure ones?

@JAForbes wow, thanks for the help (pointing out that

`chain(g, f) === converge(f, [g, identity])`

)! I should probably go and learn about all of the properties of functions and how they relate to these concepts, because this is the 2nd time I've gotten tripped up by treating functions as values
@kwijibo

I mentioned ordering only as an example of a property that doesn't define the "shape". Sets aren't ordered by nature, and the docs you mention talks about insertion order in the same way that we could do about object keys.

Regarding trees: it depends, obviously. If some kind of tree has some rule about not having duplicate leafs we may end up in the same "conundrum".

I mentioned ordering only as an example of a property that doesn't define the "shape". Sets aren't ordered by nature, and the docs you mention talks about insertion order in the same way that we could do about object keys.

Regarding trees: it depends, obviously. If some kind of tree has some rule about not having duplicate leafs we may end up in the same "conundrum".

@ram-bot

`R.chain(R.add, R.add(10))(10)`

`monad.call(...).apply is not a function`

@ram-bot

```
const chain_ = R.curry((k, f) => r => k(f(r))(r));
chain_(R.add, R.add(10))(10)
```

`30`

ramda has wrong monadic bind

Can I change key names in an object easily?

`{foo: 1, bar: 2}`

-> `{x: 1, y: 2}`

Beat me to it :)

:thumbsup:

:laughing:

@kwijibo your example is backwards

you did

`chain(f, g)`

not `chain(g, f)`

I did right version. Ramda has bug with monadic bind for function

@ram-bot

`R.chain(R.add(10), R.range(0, 10))`

`[ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 ]`

@xgrommx yup. See ramda/ramda/pull/1937

You guys have some... interesting... conventions for approving pull requests.

left and right side =)

```
// ($) :: (a -> b) -> a -> b
// (<$>) :: Functor f => (a -> b) -> f a -> f b
// (<*>) :: Applicative f => f (a -> b) -> f a -> f b
// (=<<) :: Monad m => (a -> m b) -> m a -> m b
// (<$) :: Functor f => a -> f b -> f a
// (<*) :: Applicative f => f a -> f b -> f a
// (&) :: a -> (a -> b) -> b -- Data.Function
// (<&>) :: Functor f => f a -> (a -> b) -> f b -- Control.Lens.Operators
// (<**>) :: Applicative f => f a -> f (a -> b) -> f b -- Control.Applicative
// (>>=) :: Monad m => m a -> (a -> m b) -> m b
// ($>) :: Functor f => f a -> b -> f b
// (*>) :: Applicative f => f a -> f b -> f b
// (.) :: (b -> c) -> (a -> b) -> a -> c
// (<=<) :: Monad m => (b -> m c) -> (a -> m b) -> a -> m c
// (>>>) :: Category cat => cat a b -> cat b c -> cat a c
// (>=>) :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c
```

@nateabele: how so? (beyond the fact that this is a part-time, and sometimes low-priority commitment from everyone)

:camel: and :herb:

;-)

Ah yes. The core committers each have themselves an icon. No idea why. But it's more fun than

`+1`

.
Well I'll grant you that.

Sorry to drop my comment earlier and disappear. I don't get much time here lately. Those extra

`Ord`

constraints in the Haskell version seem to make this something other than a Functor `map`

. But I may just be confused. It still feels strange, even if others are doing it.
Well, my first thought was to write a separate library that just patches all the core prototypes.

Anyway, your call. I'm happy to work up a patch next week, but I may need some help making it transducer-y.

Those extra Ord constraints in the Haskell version seem to make this something other than a Functor map

Right, due to the `Ord`

constraint on `Data.Set`

the mapping function is restricted to returning another `Ord`

instance, so it's more of a endofunctor of a something like an OrderedHask category, rather than Hask itself.

But as long as identity and associativity laws hold, then it should be fine to treat as a functor (just restricted to `Ord`

)

```
> import Data.Set
> let f = (* 42)
> let g = (** 2)
> let xs = fromList [-2, -1, 0, 1, 2]
> (Data.Set.map g) . (Data.Set.map f) $ xs
fromList [0.0,1764.0,7056.0]
> Data.Set.map (g . f) xs
fromList [0.0,1764.0,7056.0]
```

```
> :t Data.Set.map
Data.Set.map :: Ord b => (a -> b) -> Set a -> Set b
```