These are chat archives for ramda/ramda

23rd
Mar 2015
Walle Cyril
@GrosSacASac
Mar 23 2015 07:51
Many key functions now are optionally transduced --> What does it mean ?
Raine Virta
@raine
Mar 23 2015 09:48
i may understand reader monad slightly better now. i believe it could've been used in some cases instead of partial applying a function with some sort of configuration
Simon Friis Vindum
@paldepind
Mar 23 2015 10:34
Does anyone know of a general purpose library to convert non functional libraries into a functional style?
As in, it can curry functions, reorder their arguments, convert them into foobarN variants, etc.
Walle Cyril
@GrosSacASac
Mar 23 2015 11:01
@paldepind you should try a for in loop over the library and reassign with R.curry wrapped
Simon Friis Vindum
@paldepind
Mar 23 2015 11:08
@GrosSacASac Sure! But that only gives me currying. I'd also like to say: this function takes a variable amount of argument, please construct variants of it with fixed arity.
It's not a I don't know how to do it. Its just that I think such a tool would be useful. If such a think doesn't exist I might
write one.
Raine Virta
@raine
Mar 23 2015 11:11
ah. https://github.com/ramda/ramda-fantasy/pull/20/files is this the reason why i can't get access to env with ask.map?
Scott Sauyet
@CrossEye
Mar 23 2015 13:09
@paldepind lodash's rearg along with any decent curry and one additional function for arity would probably be all it takes. I don't think there's any ready-made solution to this. Ramda's invoker is a partial solution to the first, but it's not as flexible rearg.
Although perhaps what's really wanted is a combination of the features of invoker and rearg.
And of course any of this would still be manual; you'd have to do this in a function-by-function manner.
Simon Friis Vindum
@paldepind
Mar 23 2015 13:14
@CrossEye I was thinking something with a neat syntax where you can just declare what should be done to which functions. But yes, something like lodash's rearg would be needed.
Hardy Jones
@joneshf
Mar 23 2015 13:27
@raine probably. Everything was implemented in terms of chain which was broken.
that reminds me
i still need to finish that thing
Scott Sauyet
@CrossEye
Mar 23 2015 13:40
@paldepind: whether it's declarative or more imperative in its API, I think an implementation would not be overly difficult. This is something I would also like to see. I don't know if it would fit inside Ramda or would be better as a stand-alone project.
Simon Friis Vindum
@paldepind
Mar 23 2015 13:45
@CrossEye: I agree. I'll have to think some more about the most elegant way to do this.
Ludwig Magnusson
@TheLudd
Mar 23 2015 14:09

Hello.
In my code I have a list of purchases, some of them contains price. I want to sum the total amount spent for a list of purchases. My code looks like this:

  var spendSum = R.reduce(function(acc, item) {
    return acc + R.defaultTo(0, item.price);
  }, 0, purchases);

I would like to not define the body of the reduce function but instead only re-use existing functions. What I have come up with is this:

var priceOrZero = R.compose(R.defaultTo(0), R.prop('price'));
var addPrice = R.useWith(R.add, R.identity, priceOrZero);
var spendSum = R.reduce(addPrice, 0, purchases);

useWith is rather ramda specific thoug. I wonder if there is a more general solution here or is this what the rest of you would do as well?

I guess the problem is that the reduce callback gets two arguments. I often find it hard to re-use functions in reduce because of this.
Scott Sauyet
@CrossEye
Mar 23 2015 14:14
@GrosSacASac: regarding transducers, see #950.
Raine Virta
@raine
Mar 23 2015 14:15
R.reduce((acc, item) => acc + priceOrZero(item), 0, purchases)
I think lambda is more readable than useWith
alas, es6
Ludwig Magnusson
@TheLudd
Mar 23 2015 14:17
@raine but now you are implementing the body of the callback function and not reusing existing functions like add
Hardy Jones
@joneshf
Mar 23 2015 14:27
@TheLudd so reduces accumulator has the type (b, a) -> b and you're reducing over an array with type [c] right? For arbitrary types a, b, c.
Ludwig Magnusson
@TheLudd
Mar 23 2015 14:27
yes
Hardy Jones
@joneshf
Mar 23 2015 14:29
but you want to use add which has type Number -> Number -> Number, so that'd force reduces accumulator to have the type (Number, Number) -> Number
Well the naive way would be to just map over the array first and convert it to the proper type
Scott Sauyet
@CrossEye
Mar 23 2015 14:31
Which then sounds like a job for sum: R.compose (R.sum, R.map (priceOrZero))
Ludwig Magnusson
@TheLudd
Mar 23 2015 14:31
Yes but then I'd have to loop twice.
Hardy Jones
@joneshf
Mar 23 2015 14:31
yeah
Ludwig Magnusson
@TheLudd
Mar 23 2015 14:33
I am asking because I recently understood the power of using compose with map.
If have fn1 = a -> b and fn2 = b -> c and I want to go from [a] to [c] then I can do map(compose(fn2, fn1), arrayOfA)
I was wondering if there is a similar way when I am using reduce and not map
Hardy Jones
@joneshf
Mar 23 2015 14:36
well, unfortunately, because reduce is such a weak function, you can't make very many claims about how it interacts with others.
in particular, you don't get many (any?) free theorems like you stated above
Ludwig Magnusson
@TheLudd
Mar 23 2015 14:36
what is the meaning of weak in this context?
Hardy Jones
@joneshf
Mar 23 2015 14:36
weak in the sense that there are no laws about how it should behave
so you can't really derive much from its interaction with other functions like map
or compose
at lest, no more than any other function
but
Hardy Jones
@joneshf
Mar 23 2015 14:42
it looks like you want in this case is a function ((b, a) -> b) -> (a -> c) -> ((b, c) -> b) yes?
something that will transform the second arg
or i guess untupled: (b -> a -> b) -> (a -> c) -> (b -> c -> b)
Ludwig Magnusson
@TheLudd
Mar 23 2015 14:47
Yes that looks like what I want
Hardy Jones
@joneshf
Mar 23 2015 14:48
though, for composabiltiy it'd actually be better to flip the firs ttwo
right
(a -> c) -> (b -> a -> b) -> (b -> c -> b)
so
one elegant way to get what you want is with something Conal Elliot coined Semantic Editor Combinators (SEC)
umm
if you're somewhat comfortable with haskell, which it sounds like you are, this should be helpful to undesrtand the concept: http://stackoverflow.com/questions/413930/haskell-how-to-compose-not-with-a-function-of-arbitrary-arity
but it's basically a DSL for doing these sorts of operations generally
if you had some function that modified the result of a function
and a function that modified the argument
you could get what you want
Ludwig Magnusson
@TheLudd
Mar 23 2015 14:52
Well, I have not coded in haskell but I am familiar with the function notation or whatever it is called =)
Hardy Jones
@joneshf
Mar 23 2015 14:53
if we rebracket the function above, we end up with: (a -> c) -> (b -> (a -> b)) -> (b -> (c -> b))
same function
but you can kind of see now that you want the reduce accumulator of type (b -> (a -> b)) to become (b -> (c -> b))
so you want to modify the argument of the result of the reduce accumulator
does that make sense?
the result of the reduce accumulator (b -> (a -> b)) is the function (a -> b)
the argument of the result of the reduce accumulator (b -> (a -> b)) is a
Ludwig Magnusson
@TheLudd
Mar 23 2015 14:59
Yes. I think I follow and I think I have reasoned somewhat along these lines previously
Hardy Jones
@joneshf
Mar 23 2015 14:59
great!
so if you have some dsl that gives you result and argument functions, you could make your little converter
it'd be (result . argument $ f) (+) in haskell syntax
or in js...
R.compose(result, argument)(f)(R.add)
so now it just suffices to derive the dsl
first let's look at result
you want to go into a function
and modify the result with another function
so you want something like: (b -> c) -> (a -> b) -> (a -> c)
where the first function is the modifier
and the second is the thing being modified
but wait, that's (.) in haskell and R.compose in ramda!
This message was deleted
Hardy Jones
@joneshf
Mar 23 2015 15:04
now, what about argument?
you want to go into a function, and modify the input with another function
so you want something like: (c -> a) -> (a -> b) -> (c -> b)
which with renaming is: (a -> b) -> (b -> c) -> (a -> c)
just renaming the arbitrary type variables
well that's flip (.) in haskell and R.pipe in ramda!
so there you go
ramda already gives you some semantic editor combinators
alias them with fixed arity so things go well...
Hardy Jones
@joneshf
Mar 23 2015 15:10
var result = R.binary(R.compose)
var argument = R.binary(R.pipe)
actually, I dunno that that does the right thing, but hopefully that returns a curried version
if not use arity or nAry or whatever does the rgith thing
then you should be able to throw together your wanted thing
R.reduce(R.compose(result, argument)(priceOrZero)(R.add), 0, purchases)
Ludwig Magnusson
@TheLudd
Mar 23 2015 15:13
let me try that out..
Hardy Jones
@joneshf
Mar 23 2015 15:17
heh, i'm just trying it outnow :)
not working too well
i think the currying is dieing somewheres
Ludwig Magnusson
@TheLudd
Mar 23 2015 15:19
What about result expecting two arguments but being first in compose?
Hardy Jones
@joneshf
Mar 23 2015 15:20
well, i'm converting between haskell and js so that might be an issue :) but let's work through the types
compose : (b -> c) -> (a -> b) -> (a -> c)
result : (b -> c) -> (a -> b) -> (a -> c)
argument : (a -> b) -> (b -> c) -> (a -> c)
rebracketed:
compose : (b -> c) -> (a -> b) -> (a -> c)
result : (b -> c) -> ((a -> b) -> (a -> c))
argument : (a -> b) -> ((b -> c) -> (a -> c))
acrually, that's going to get confusing
:)
Ludwig Magnusson
@TheLudd
Mar 23 2015 15:25
I'll have to confess I'm a bit confused already =)
Hardy Jones
@joneshf
Mar 23 2015 15:25
haha
sorry, it's a bit awkward at first
R.compose(result, argument)(priceOrZero)(R.add)(0)({price: 30}) //=> 30
so i think it works
sometihng iwht the reduce doesn't like it though
var result = R.curry(R.nAry(2, R.compose));
var argument = R.curry(R.nAry(2, R.pipe));
var priceOrZero = R.compose(R.defaultTo(0), R.prop('price'));
var purchases = [
  {price: 30},
  {price: 10},
  {price: 6}
];

R.reduce(R.compose(result, argument)(priceOrZero)(R.add), 0, purchases);
that's what i've got
R.compose(result, argument)(priceOrZero)(R.add)(0)(purchases[0]) // => 30
R.compose(result, argument)(priceOrZero)(R.add)(R.compose(result, argument)(priceOrZero)(R.add)(0)(purchases[0]))(purchases[1]) //=> 40
so the individual steps work, but reduce doesn't work with it
Hardy Jones
@joneshf
Mar 23 2015 15:45
yeah, they've gotta be curried
Santi Albo
@santialbo
Mar 23 2015 15:50
is there a way of swapping arguments? i'd like an isInArray function by swapping the arguments of contains
Ludwig Magnusson
@TheLudd
Mar 23 2015 15:50
flip?
Santi Albo
@santialbo
Mar 23 2015 15:50
nice thanks!
Hardy Jones
@joneshf
Mar 23 2015 15:51
I had to make sure i wasn't crazy: http://lpaste.net/128357
@TheLudd i'm sorry, I'm not sure what's going wrong here in jsland. The idea is there and you should be able to do what you want in theory.
and ramda even provides all the stuff you need to do generally
Ludwig Magnusson
@TheLudd
Mar 23 2015 15:54
Well thanks for all the input and effort
Hardy Jones
@joneshf
Mar 23 2015 15:54
I just can't plumb it together :(
no prob
SEC is an interesting concept
Ludwig Magnusson
@TheLudd
Mar 23 2015 15:56
But basically, all I need is a transform/reduce where each element in the list is passed through a transform function before it is put into the reduce accumulator
Hardy Jones
@joneshf
Mar 23 2015 16:00
oh, I think I got it!
var result = R.curryN(2, R.compose);
var argument = R.curryN(2, R.pipe);
var priceOrZero = R.compose(R.defaultTo(0), R.prop('price'));
var purchases = [
  {price: 30},
  {price: 10},
  {price: 6}
];

R.reduceRight((acc, x) => R.compose(result, argument)(priceOrZero)(R.add)(acc)(x), 0, purchases); //=> 46
weird stuff
maybe someone more well versed can explain why that had to be
just to drive the point home
Hardy Jones
@joneshf
Mar 23 2015 16:06
SEC is a dsl for working generically with functions and data types
allows you to write things point free
and really are just aliases for things that already exist
Ludwig Magnusson
@TheLudd
Mar 23 2015 17:16
@joneshf I tried to uncomplicate things...
or why not paste here:
var transformBinaryRight = function(binaryFn, transformer) {
  return function(a, b) {
    return binaryFn(a, transformer(b));
  };
};

var arrayOfStrings = [ '1', '2', '3' ];
var parseAndAdd = transformBinaryRight(R.add, parseInt);
R.reduce(parseAndAdd, 0, arrayOfStrings);
I changed the use case to parsing number strings before adding them, but it is still the same general situation
Hardy Jones
@joneshf
Mar 23 2015 17:31
that works as well
i'm still confused why reduce didn't like that curried function
Ludwig Magnusson
@TheLudd
Mar 23 2015 17:35
perhaps a run with a debugger will give a clue
Hardy Jones
@joneshf
Mar 23 2015 17:51
hmm, the transducer thing is making a bit harder to undesrtand what's going on
looks like whatever if the equivalent of this line: https://github.com/ramda/ramda/blob/585448560f3c164ed61c1437f0857152d2013a86/src/internal/_reduce.js#L4 would need to be explicitly curried?
that doesn't seem right thogh
i thought things were just supposed to work
Ludwig Magnusson
@TheLudd
Mar 23 2015 17:56
does it work with an older version? pre transduce?
Hardy Jones
@joneshf
Mar 23 2015 17:57
i went back to 0.10, and no change
Scott Sauyet
@CrossEye
Mar 23 2015 18:01
On the other hand, it sounds as though transducers are exactly what you want. A good part of the point of them is to compose the data transformation separate from the grouping.
Ludwig Magnusson
@TheLudd
Mar 23 2015 18:02
Time to read up on them then
Hardy Jones
@joneshf
Mar 23 2015 18:07
yeah, it does seem like this is prime for transduce
i wonder about that type in the documentation though
shouldn't it be (b -> c) -> ((a, c) -> a) -> a -> [b] -> a ?
since each b in the array is passed to the first function before the second one.
Hardy Jones
@joneshf
Mar 23 2015 18:21
i'm batting 1000
TypeError: n.step is not a function
is that not how you're supposed to use it?
Scott Sauyet
@CrossEye
Mar 23 2015 18:30
I'm still trying to get a handle on transducers. #950 is a step in that direction.
seems to work
Ludwig Magnusson
@TheLudd
Mar 23 2015 18:37
@joneshf Nice. Looks like you can remove compose
Also. If I remove map there is an error but the result is still there also
Hardy Jones
@joneshf
Mar 23 2015 18:38
interesting
Ludwig Magnusson
@TheLudd
Mar 23 2015 18:39
perhaps just a leftover..
Hardy Jones
@joneshf
Mar 23 2015 18:39
the first part
yeah
Ludwig Magnusson
@TheLudd
Mar 23 2015 18:40
Ok, so the answer I was looking for: R.transduce(R.map(priceOrZero), R.add, 0, purchases);
Very nice
Hardy Jones
@joneshf
Mar 23 2015 18:40
:)
Ludwig Magnusson
@TheLudd
Mar 23 2015 18:40
@joneshf If you were here I'd give you a whiskey..
Hardy Jones
@joneshf
Mar 23 2015 18:41
so long as you share it with @CrossEye
Ludwig Magnusson
@TheLudd
Mar 23 2015 18:41
ofc
But seriously you seemed to put a lot of energy into this =)
Hardy Jones
@joneshf
Mar 23 2015 18:43
i like Semantic Editor Combinators
;)
erm
just realized if you pronounce that as an acronym it sounds dirty
Ludwig Magnusson
@TheLudd
Mar 23 2015 18:45
But on the topic of transducers: As I understand this is a good use case for them but they also have other uses correct?
Hey I'm Swedish, not a problem here ;)
Hardy Jones
@joneshf
Mar 23 2015 18:46
heh
Hardy Jones
@joneshf
Mar 23 2015 18:54
yeah, in general there should be more uses, I'm not sure if the ramda version is more general than just array though
This message was deleted
Scott Sauyet
@CrossEye
Mar 23 2015 18:55
I
Raine Virta
@raine
Mar 23 2015 18:58
how come transducers are such a recent invention, or did they just have a different name before rich hickey brought them up?
Hardy Jones
@joneshf
Mar 23 2015 18:59
the idea has been tossed around a few times under different names and with different levels of power
Elliot with his SEC stuff
van Laarhoven and his lenses
some more powerful, some weaker
Raine Virta
@raine
Mar 23 2015 19:01
right. can't wait to read more about them (again), now that ramda has them
is this known?
David Chambers
@davidchambers
Mar 23 2015 20:08
Could you open an issue for that, @joneshf? It's not specific to R.reduce: Ramda's higher-order functions provide all their arguments at once, so don't currently work with regularly curried functions.
Hardy Jones
@joneshf
Mar 23 2015 20:14
sure
#970
Raine Virta
@raine
Mar 23 2015 20:54
compose(fromPairs, map(function(tmpl) {
  return [ tmpl, compile(tmpl) ];
}));
is there a better pattern for this?
[s] => {s: fn(s)}
Michael Hurley
@buzzdecafe
Mar 23 2015 21:09

Ok, so the answer I was looking for: R.transduce(R.map(priceOrZero), R.add, 0, purchases);

@TheLudd @joneshf this is so nice i added it to the repl as an example

Ludwig Magnusson
@TheLudd
Mar 23 2015 21:10
cool =)
Raine Virta
@raine
Mar 23 2015 21:51
after trying to use some monads in javascript i think i've got a better understanding why haskell needs monads and why javascript can get away without them. however i'm not certain yet about the value of pure functions in a non-typed language, where referential transparency is not guaranteed
Jason Marmon
@jtmarmon
Mar 23 2015 21:52
i'm super confusedright now - why do i see [Function: _and] when I log R.and(undefined, undefined)
Ludwig Magnusson
@TheLudd
Mar 23 2015 21:53
@jtmarmon I think the answer is here: ramda/ramda#836
Hardy Jones
@joneshf
Mar 23 2015 21:53

@raine for your example up there, might be instructive to write the function as

compose(fromPairs, map(function(tmpl) {
  return [ identity(tmpl), compile(tmpl) ];
}));

Maybe you can find some pattern there

Ludwig Magnusson
@TheLudd
Mar 23 2015 21:54
Or maybe I was wrong
Hardy Jones
@joneshf
Mar 23 2015 21:54
@raine probably something might make sense that way.
@buzzdecafe awesome!
Ludwig Magnusson
@TheLudd
Mar 23 2015 21:55
@joneshf Do you know how to run two Futures in parallel and act on the result when they are both done?
Hardy Jones
@joneshf
Mar 23 2015 21:57
@raine as far as purity and referential transparency, that can be said of anything in a dynamic language like js. But we shouldn't give up on good ideas.
Documentation, for example, means just as much(little?) as purity in js.
But I think we all want good documentation. :)
Jason Marmon
@jtmarmon
Mar 23 2015 21:59
hmm not seeing the answer in that thread @TheLudd (or maybe i'm not understanding it correctly)...the docs provide really simple examples: R.and(false, true); //=> true so I don't understand what's going on here. it must be a bug, right?
Hardy Jones
@joneshf
Mar 23 2015 22:00

@TheLudd sounds like something ap should do, but it probably depends on how ap is implemented for whatever Future you're using.

Also probably depends on ap existing for the Future data type you're using.

Ludwig Magnusson
@TheLudd
Mar 23 2015 22:00
I tried some lifting but it ended up doing stuff sequentially
Hardy Jones
@joneshf
Mar 23 2015 22:00
what implementation are you using?
it might only work sequentially
until someone writes a parallel implementation for it
Ludwig Magnusson
@TheLudd
Mar 23 2015 22:01
ramda-fantasy and folktales Task
They both chain in their ap which makes it sequential
could it be done otherwise?
Jason Marmon
@jtmarmon
Mar 23 2015 22:03
ah yes - it was because I was on 0.9 ramda/ramda#953. would be great to get version nubmers in the docs
Ludwig Magnusson
@TheLudd
Mar 23 2015 22:12
DrBoolean mentioned something about traversein his video but I haven't found a working imlpementation.
Hardy Jones
@joneshf
Mar 23 2015 22:17
@TheLudd yeah, it's possible to have it run ap in parallel. It would require a different implementation though.
Michael Hurley
@buzzdecafe
Mar 23 2015 23:43

Do you know how to run two Futures in parallel and act on the result when they are both done?

this may be a use case for commute! that would let you convert a list of futures into a future of a list