These are chat archives for ramda/ramda

10th
Mar 2015
Nate Wildermuth
@wildermuthn
Mar 10 2015 04:35
Are reduceIndexed or merge very slow?
I just cut down an operation from 7 seconds to 1ms.
            // 7 seconds
            var makeKey = function (acc, obj, index) {
               return R.merge(acc, {[obj.timestamp]: index});
            }
            var timeMap = R.reduceIndexed(makeKey, {}, timeline);

            // 1 ms
            var timeMap = {};
            _.each(timeline, function(obj, index) {
              timeMap[obj.timestamp] = index;
            });
I suppose I'm probably doing it wrong, but I'm scratching my head a bit.
John-David Dalton
@jdalton
Mar 10 2015 04:39
you can also do:
var timeMap = _.transform(timeline, function(result, obj, index) {
  result[obj.timestamp] = index;
}, {});
Nate Wildermuth
@wildermuthn
Mar 10 2015 04:41
Interested to see if that performs better. Also to understand why Ramda's performance would differ so dramatically, and what I could to to avoid it.
Nate Wildermuth
@wildermuthn
Mar 10 2015 04:52
// 15ms
var timeMap = {};
R.mapIndexed((e, i) => timeMap[e.timestamp] = i, timeline);
So this is easier to read. Not quite 1ms, but fast enough for my purposes.
John-David Dalton
@jdalton
Mar 10 2015 04:53
All es6 n stuff : D
Nate Wildermuth
@wildermuthn
Mar 10 2015 04:54
Can't do it any other way without it looking horrible... compare to transform:
var timeline = _.transform(timeline, (r, obj, i) => r[obj.timestamp] = i, {});
John-David Dalton
@jdalton
Mar 10 2015 04:55
how come transform doesn't get those 1 char var names : P
Nate Wildermuth
@wildermuthn
Mar 10 2015 04:55
lol
Would that work?
I will say that Ramda has gotten me used to putting the function first. Reminds me of lisp.
John-David Dalton
@jdalton
Mar 10 2015 04:58
you're wanting to iterate over timeline not set it to an empty object
Nate Wildermuth
@wildermuthn
Mar 10 2015 05:00
Thanks for the help, @jdalton!
John-David Dalton
@jdalton
Mar 10 2015 05:00
var timeMap = _.transform(timeline, (r, o, i) => r[o.timestamp] = i, {});
yap yap
John-David Dalton
@jdalton
Mar 10 2015 06:34
Ramda's lazy eval activity got me thinking I could apply the lazy chaining optimizations to _.flow/_.flowRight and ~10 LOC later:
This message was deleted
Now to polish : D
David Chambers
@davidchambers
Mar 10 2015 07:12
I've opened a pull request to add a pattern-matching function to Sanctuary: plaid/sanctuary#12. Usage example:
//  evaluate :: Expr -> Number
var evaluate = S.match([
  [Val, identity],
  [App, function(op, l, r) {
    return S.match([
      [Add, function() { return evaluate(l) + evaluate(r); }],
      [Sub, function() { return evaluate(l) - evaluate(r); }],
      [Mul, function() { return evaluate(l) * evaluate(r); }],
      [Div, function() { return evaluate(l) / evaluate(r); }],
    ], op);
  }],
]);
Feedback much appreciated. :)
Hardy Jones
@joneshf
Mar 10 2015 07:25
nice!
Ludwig Magnusson
@TheLudd
Mar 10 2015 10:02

Is there a function that does this in ramda?

function (arg, fn) {
  return fn(arg)
}

The use case is to have a list of functions that should all be called with the same argument.,

R.all(R.I)?
Raine Virta
@raine
Mar 10 2015 10:40
https://gist.github.com/raine/2b6f5c4ef03582bb0de1 this is pretty neat but you can't store any context about the problem in the failed url. boolean is dumb. maybe some monad would help
Scott Sauyet
@CrossEye
Mar 10 2015 11:32
@wildermuthn you could probably also do this with mapIndexed and fromPairs. I'm sure it's calling merge many times that's causing your issue. Ramda is very unlikely to ever have something like transform, whose entire purpose is to continually mutate an input object.
Scott Sauyet
@CrossEye
Mar 10 2015 12:44
@raine There are discussions about adding such an and in #843, but it's somewhat controversial. Right now R.and:: [a -> Bool] -> (a -> Bool).
Raine Virta
@raine
Mar 10 2015 14:14
@CrossEye thanks
Raine Virta
@raine
Mar 10 2015 15:31
{k: {k: v, ...}} I need to clone the object but omit some kv pairs in the objects the are values, node (iojs) crashes when I try to clone the whole object, probably because one of the values is a Buffer
evolve could almost be applied but the keys need to be known beforehand
I think lodash's transform could do it
actually R.mapObj might do it
Hardy Jones
@joneshf
Mar 10 2015 16:58
@TheLudd looks like apply: http://ramdajs.com/docs/#apply
well flipped
also, your description is Reader.
Ludwig Magnusson
@TheLudd
Mar 10 2015 16:59
A list of functions that should be called with the same argument === Reader?
Hardy Jones
@joneshf
Mar 10 2015 17:00
not necessarily a list, but just calling multiple functions with the same argument
Scott Sauyet
@CrossEye
Mar 10 2015 17:29
I think apply had more to do with the conversion of variadic functions to ones operating on a list: var max = R.apply (Math.max); max ([8, 6, 7, 5, 3, 0, 9]); //=> 9
Hardy Jones
@joneshf
Mar 10 2015 17:30
oh?
hmm, looks like it.
Scott Sauyet
@CrossEye
Mar 10 2015 17:31
I don't think Ramda had quite what you're looking for, @TheLudd, but you might be able to create it as, say, R.flip (R.nAry (2, R.call)).
Yes, there's a dual unapply.
Ludwig Magnusson
@TheLudd
Mar 10 2015 17:32
Think I'll just go with the implementation I posted above =)
Scott Sauyet
@CrossEye
Mar 10 2015 17:34
but presumably you'll want to curry it too, no?
Hardy Jones
@joneshf
Mar 10 2015 17:35
what's the process for adding something like that?
Ludwig Magnusson
@TheLudd
Mar 10 2015 17:37
Yes
Scott Sauyet
@CrossEye
Mar 10 2015 17:38
Just raising an issue or even better submitting a pull request on GitHub. @TheLudd is certainly familiar with it. But this is a useful way too check to see if it already exists.
John-David Dalton
@jdalton
Mar 10 2015 18:55

@CrossEye

Ramda is very unlikely to ever have something like transform, whose entire purpose is to continually mutate an input object.

Naw, transform works very much like reduce in that it allows devs to augment an accumulator value.

Hardy Jones
@joneshf
Mar 10 2015 19:18
I can't for the life of my figure out what transform actually does.
John-David Dalton
@jdalton
Mar 10 2015 19:19
transform is like reduce, except that it allows exiting early and will create an accumulator based on the type of value you're iterating over (if an accumulator is not provided)
Hardy Jones
@joneshf
Mar 10 2015 19:20
so it's a procedural loop?
Robin Lambertz
@roblabla
Mar 10 2015 19:20
I would expect a function named transform to be closer to map than to reduce :|
John-David Dalton
@jdalton
Mar 10 2015 19:21
map can be created by way of reduce
its all in how you look at it
Hardy Jones
@joneshf
Mar 10 2015 19:44
is there a version of pipe or compose that specifically takes two functions?
Robin Lambertz
@roblabla
Mar 10 2015 19:46
R.binary(R.pipe) ?
Hardy Jones
@joneshf
Mar 10 2015 19:46
ah
thanks
alright, what about a pre-curried version :)
I know i can just R.curry(R.binary(R.pipe))
but is there anything that does it already?
Robin Lambertz
@roblabla
Mar 10 2015 19:51
isn't R.binary's result curried ?
Robin Lambertz
@roblabla
Mar 10 2015 19:53
R.curryN(2, R.add)
;)
Hardy Jones
@joneshf
Mar 10 2015 19:54
great!
thanks
John-David Dalton
@jdalton
Mar 10 2015 19:56
Keep in mind curryN doesn't cap args though
var r = R.curryN(2, function(a,b,c) { return [a,b,c]; });
r(1)(2, 3);
// => [1,2,3]
Hardy Jones
@joneshf
Mar 10 2015 20:07
well that's confusing
Robin Lambertz
@roblabla
Mar 10 2015 20:18
That's... odd.
Looks like let binaryCurry = R.curry(R.binary); is going to be the way to go :P
David Chambers
@davidchambers
Mar 10 2015 20:19
It's to support functions with optional arguments. There's actually an argument to be made for Ramda ignoring the existence of such functions. It would simplify a few things.
Robin Lambertz
@roblabla
Mar 10 2015 20:19
oh, I see.
David Chambers
@davidchambers
Mar 10 2015 20:21
In such discussions @CrossEye tends to favour the route that allows Ramda to better interoperate with JavaScript code written in different ways (optional arguments, variadic functions, OOP).
Robin Lambertz
@roblabla
Mar 10 2015 20:22
Well, I'm of a similar opinion, but I would expect R.curryN to be a shortcut for R.curry(R.nAry)
And R.nAry, AFAIK, doesn't really support "optional arguments".
Jethro Larson
@jethrolarson
Mar 10 2015 20:23
I know David'll hate me but I have a PR out for #843. ducks
David Chambers
@davidchambers
Mar 10 2015 20:24
@jethrolarson: Haha, yes! I'm happy to be overruled, but I'll make my case. :)
@roblabla: Funnily enough, R.nAry exists due to the existence of functions with optional arguments. It provides a way to prevent optional arguments from being supplied. Here's the canonical example:
> ['10', '10', '10'].map(parseInt)
[ 10, NaN, 2 ]
> ['10', '10', '10'].map(R.nAry(1, parseInt))
[ 10, 10, 10 ]
Robin Lambertz
@roblabla
Mar 10 2015 20:26
@davidchambers Makes sense, but what's the use-case for curryN then ?
Oh
David Chambers
@davidchambers
Mar 10 2015 20:27
curryN is for currying a function which does not correctly report its arity.
Robin Lambertz
@roblabla
Mar 10 2015 20:27
Yeah, if Function.length is wrong.
I see.
David Chambers
@davidchambers
Mar 10 2015 20:28
One could see it as sugar for curry(arity(n, f)).
Hardy Jones
@joneshf
Mar 10 2015 20:44
all these arity functions are confusing
David Chambers
@davidchambers
Mar 10 2015 20:49
I completely agree.
Robin Lambertz
@roblabla
Mar 10 2015 20:52
Well, arity makes sense. nAry, binary, etc... could get a better name, since what they really do is cap the max amount of parameters. That said, I think things are okay as they are.
Martin Algesten
@algesten
Mar 10 2015 20:52
curryN seems a bit superflous. why not just drop it?
for clarity
Scott Sauyet
@CrossEye
Mar 10 2015 20:52
But they're there because the language is schizophrenic about function arity..
Robin Lambertz
@roblabla
Mar 10 2015 20:53
@algesten functions which use arguments instead of specifying parameters break with R.curry
Hardy Jones
@joneshf
Mar 10 2015 20:53
maybe they just lack a good tutorial?
Martin Algesten
@algesten
Mar 10 2015 20:54
yes. but something like curry(binary(f)) is much clearer than curryN(2,f)
Hardy Jones
@joneshf
Mar 10 2015 20:54
the documentation is good if you already know what each does, and maybe you forget which name does which, or you need a quick reference
but perhaps an indepth explanation of each with numerous examples would be a great addition
Robin Lambertz
@roblabla
Mar 10 2015 20:54
@algesten that doesn't do the same thing, that's how the whole discussion started :)
Hardy Jones
@joneshf
Mar 10 2015 20:54
blog post, or some such
Robin Lambertz
@roblabla
Mar 10 2015 20:55
I agree a Ramda tutorial would be awesome.
Scott Sauyet
@CrossEye
Mar 10 2015 20:55
curryN allows you to curry a function that uses the arguments object or which had a named optional parameter you're happy to ignore.
Martin Algesten
@algesten
Mar 10 2015 20:55
but surely to curry you only need to get the function to report correct arity (i.e. Function.length) it can still accept varags?
Robin Lambertz
@roblabla
Mar 10 2015 20:56
curry and varargs are kind of mutually exclusive.
['10', '10', '10'].map(parseInt)
Martin Algesten
@algesten
Mar 10 2015 20:57
not really. curry(binary(pipe)) is a pipe that expects 2 arguments.
but you still could call it with more.
Robin Lambertz
@roblabla
Mar 10 2015 20:57
There's no variadic argument in there.
you can, but they are ignored.
Martin Algesten
@algesten
Mar 10 2015 20:57
well. should they be?
Robin Lambertz
@roblabla
Mar 10 2015 20:57
with curryN they are not ignored
Martin Algesten
@algesten
Mar 10 2015 20:57
why clamp the arity unless you have to?
ok. so that’s the rationale for curryN
Robin Lambertz
@roblabla
Mar 10 2015 20:58
well, I guess that's where we draw the line. What should the default curryN do, clamp arguments or not ? curryN currently just makes sure the "minimum amount of arguments" is met, but you can still provide it more as the last call to the curry function.
Martin Algesten
@algesten
Mar 10 2015 20:59
it’s only really madness like parseInt that needs clamping. isn’t it otherwise better to just allow varags?
i guess what i say is that i’d like curry(binary(f)) be equivalent to curryN(2,f). which meant the latter can be removed.
Robin Lambertz
@roblabla
Mar 10 2015 21:00
Well, when someone uses curryN, it means function reports incorrect arity, ergo function uses arguments object, right ? So you might need to clamp args.
Martin Algesten
@algesten
Mar 10 2015 21:01
clamping and reporting are two different things.
you can make a function report arity x without it being clamped to x.
which is sufficient for currying.
Robin Lambertz
@roblabla
Mar 10 2015 21:01
Hmmhmm.
wait so you want curryN to clamp ?
cuz curry(binary(f)) would clamp ^^.
Martin Algesten
@algesten
Mar 10 2015 21:02
or the reverse actually, none of them clamp :D
binary(f) makes a function that reports arity 2. but accepts varargs.
Robin Lambertz
@roblabla
Mar 10 2015 21:03
nope
Martin Algesten
@algesten
Mar 10 2015 21:03
(z) -> (a,b) -> z arguments…
Robin Lambertz
@roblabla
Mar 10 2015 21:03
Any extraneous parameters will not be passed to the supplied function.
Martin Algesten
@algesten
Mar 10 2015 21:03
ok. that may be the case now. i’m just saying what i think should happen ;)
Robin Lambertz
@roblabla
Mar 10 2015 21:03
oh.
I see.
oh, yeah, actually, now that I think about it, that could be good
Martin Algesten
@algesten
Mar 10 2015 21:04
it kind of makes it more javascripty and still works well with currying.
Robin Lambertz
@roblabla
Mar 10 2015 21:04
remove nAry, make binary use arity, and add a new "clamp" function to replace nAry for the rare cases it is needed
Martin Algesten
@algesten
Mar 10 2015 21:04
exactly. because the cases where you need clamping are not that often.
Danny Fritz
@dannyfritz
Mar 10 2015 21:05
i kind of think nothing curried should support varArgs
Hardy Jones
@joneshf
Mar 10 2015 21:05
@dannyfritz :+1:
Robin Lambertz
@roblabla
Mar 10 2015 21:05
I've never had to curry a function that had vararg, so I don't really see the usecase :P
Martin Algesten
@algesten
Mar 10 2015 21:06
concat = curry binary (as...) -> [].concat as…
Robin Lambertz
@roblabla
Mar 10 2015 21:06
well, apart from parseInt.
Martin Algesten
@algesten
Mar 10 2015 21:06
handy that array concat could be used curried as binary, but we can also allow curry a,b,c
pardon my coffee
Danny Fritz
@dannyfritz
Mar 10 2015 21:07
I don't think parseInt is varArgs. the problem is the 2nd argument we pass in is commonly the index and we don't want it to be.
you should partialRight parseInt i believe, not clamp it
Martin Algesten
@algesten
Mar 10 2015 21:09
another example, commutative maths functions:
add = curry binary (as...) -> reduce as, (a,b) -> a + b
handy that they are curried, but can be nice as varags.
Robin Lambertz
@roblabla
Mar 10 2015 21:11
the biggest problem I have with (real) curried vararg is that "eventually" (once all the arguments are given) you lose its curried property.
Scott Sauyet
@CrossEye
Mar 10 2015 21:21
parseInt is an example of a general issue, one different from the use of the arguments object: named optional parameters.
Robin Lambertz
@roblabla
Mar 10 2015 21:24
@CrossEye but the problem with parseInt isn't for the currying.
Scott Sauyet
@CrossEye
Mar 10 2015 21:26
Actually Ramda shouldn't have any problem with parseInt. It does't pass index parameters in map et al.
Scott Sauyet
@CrossEye
Mar 10 2015 21:36
Sorry for poor formatting; don't know how to do better here on my mobile. Imagine this: curryN (2, function makeCircle (origin, radius, options) { ...} where options might include otherwise defaulyed values such as color or texture.
You might want that curried to two parameters, but if someone called the curried one with the third, it's useful to pass it through.
Robin Lambertz
@roblabla
Mar 10 2015 21:39
var circleFromOrig = curriedMakeCircle([0,0])
var circleFromOrigRad1 = circleFromOrig(1);
circleFromOrigRad1({ color: "red" });
Scott Sauyet
@CrossEye
Mar 10 2015 21:39
Hey
Robin Lambertz
@roblabla
Mar 10 2015 21:39
This isn't possible.
;)
Scott Sauyet
@CrossEye
Mar 10 2015 21:42
Right. It doesn't curry that far. But currying in Ramda allows you to pass as many parameters at any stage as you like.
Robin Lambertz
@roblabla
Mar 10 2015 21:42

Doing circleFromOrigRad1 = R.binary(circleFromOrig, 2)(1); would work, but then the resulting function is clamped, so you can't append any more optional params.

I think the main issue is the fact that binary, unary, etc... actually clamp the value, instead of just changing the reported arity.

Scott Sauyet
@CrossEye
Mar 10 2015 21:44
circleFromOrig (1, {color: 'red'})
Robin Lambertz
@roblabla
Mar 10 2015 21:44
You'd expect, e.g., R.curryN(2, fun) to be essentially the same as R.curry(R.binary(fun)), but it really isn't. The former allows varargs and optional arguments to be still provided, the later doesn't.
David Chambers
@davidchambers
Mar 10 2015 21:45
How about removing R.nAry and its partially applied forms? I think it perfectly acceptable to require a user to write wrapper functions for interop.
Scott Sauyet
@CrossEye
Mar 10 2015 21:45
It's the difference between the two different types of arity functions in Ramda, arity and nAry.
What's the advantage of that, @ddavidchambers?
Robin Lambertz
@roblabla
Mar 10 2015 21:47

nAry is a bit of a weird "type" haha.

I really thing arity functions should just change reported arity, and R.nAry should be renamed R.clamp or something similar, since this is its main use-case. It seems more consistent. Those are just my 2c

Martin Algesten
@algesten
Mar 10 2015 21:47
@roblabla is saying it :)
And let binary just change reported arity.
Not clamp.
David Chambers
@davidchambers
Mar 10 2015 21:52
@CrossEye: It's just an idea. But we are devoting five functions (nAry, nullary, unary, binary, and ternary) to a concept which is only applicable to interop. Based on this discussion there's some confusion as to what role these functions play.
Scott Sauyet
@CrossEye
Mar 10 2015 21:56
There really is a place for another level of documentation, a tutorial level. To me the main point of binary et. al. is the clamping.
David Chambers
@davidchambers
Mar 10 2015 21:58
It is to me, too, but I can understand the confusion.
Martin Algesten
@algesten
Mar 10 2015 21:59
Could you elaborate? Isn’t the point the reported arity? When do you use it for clamping?
David Chambers
@davidchambers
Mar 10 2015 22:00
Here's one example:
> ['10', '10', '10'].map(parseInt)
[ 10, NaN, 2 ]
> ['10', '10', '10'].map(R.nAry(1, parseInt))
[ 10, 10, 10 ]
If you're in a context where more arguments are being provided than you wish to provide, you can use R.nAry to swallow the unwanted args.
Martin Algesten
@algesten
Mar 10 2015 22:01
Yes but I don’t think it’s a good example since a) Ramda doesn’t do map like that and b) How often do we need to deal with bad optional args?
David Chambers
@davidchambers
Mar 10 2015 22:01
I agree, which is why I think we should consider removing these altogether.
Martin Algesten
@algesten
Mar 10 2015 22:02
But then reported arity is another thing altogether.
I can see the usefulness of binary for cutting down varargs.
Scott Sauyet
@CrossEye
Mar 10 2015 22:45
I've worked with plenty of libraries that offered a final options argument that I wanted to suppress in one circumstance or another.