These are chat archives for ramda/ramda

3rd
Aug 2017
Joey Figaro
@joeyfigaro
Aug 03 2017 01:18
Hey guys - I could use some eyes on something. I’m writing a script to merge objects that have matching identifiers - that part is done. The part I need help on is here: http://joeysharesthings.com/1w2w262N3q2w
const update_customer_safely = R.when(
    R.not(R.isNil),
    R.evolve({ email: R.prop('email') })
);
let match;

R.map(customer => {
        match = get_matching_contractor(customer)(contractors).value;
        ...
I’m mapping over customers from stripe, finding matches with objects in our database, and need to evolve the customer object using the matched db object.
(I’m adding the email from db objects to customer objects)
I’m trying to figure out how I can get that evolve in update_customer_safely ready to accept the db object and the customer object.
Does that second argument to evolve need a placeholder?
Matthew Willhite
@miwillhite
Aug 03 2017 01:24
@joeyfigaro you could just define update_customer_safely to take 2 arguments, it wouldn’t be point free, but I’d bet it reads better than any alternative.
Also note that if email doesn’t exist on the object that you are evolving, it will be ignored
Joey Figaro
@joeyfigaro
Aug 03 2017 01:25
That’s totally fine - and thanks!
Marek Stasikowski
@kosmotaur
Aug 03 2017 08:49

hi everyone, I am working on this snippet of code, and for the life of me I can't figure out how to mix in R.head into my comp function to just get the first element of the resulting array:

const o = {foo: {a:1,b:5}};
const fn1 = (obj, k) => obj[k];
const fn2 = (obj, k) => obj[k] + 5
const comp = R.pipe(
  R.prop('foo'),
  R.juxt([R.curry(fn1), R.curry(fn2)])
)

comp(o)('a') // [1, 6]

REPL: http://ramdajs.com/repl/?v=0.24.1#?const%20o%20%3D%20%7Bfoo%3A%20%7Ba%3A1%2Cb%3A5%7D%7D%3B%0Aconst%20fn1%20%3D%20%28obj%2C%20k%29%20%3D%3E%20obj%5Bk%5D%3B%0Aconst%20fn2%20%3D%20%28obj%2C%20k%29%20%3D%3E%20obj%5Bk%5D%20%2B%205%0Aconst%20comp%20%3D%20R.pipe%28%0A%20%20R.prop%28%27foo%27%29%2C%0A%20%20R.juxt%28%5BR.curry%28fn1%29%2C%20R.curry%28fn2%29%5D%29%0A%29%0A%0Acomp%28o%29%28%27a%27%29

Philipp Wille
@Yord
Aug 03 2017 09:06
Hi @kosmotaur! Whenever I encounter a problem like this, I explicitly write out all parameters. That helps me with analyzing what is happening. So as a first step, this is your comp function with explicit parameters:
const comp = o => a =>
  R.pipe(
    o => R.prop('foo')(o),
    o => R.juxt([R.curry(fn1), R.curry(fn2)])(o)
  )(o)(a)

comp(o)('a')
Marek Stasikowski
@kosmotaur
Aug 03 2017 09:07
thanks :) let's give it a shot
Philipp Wille
@Yord
Aug 03 2017 09:07
As can now be seen, the pipe function takes two parameters, the o parameter as a parameter for the function composed by pipe, and the a parameter for the function that the composed function returns when being applied.
That means, that you need to apply head after the second call to pipe, like:
const comp = o => a => R.pipe(
  a => R.pipe(
    o => R.prop('foo')(o),
    o => R.juxt([R.curry(fn1), R.curry(fn2)])(o)
  )(o)(a),
  R.head
)(a)

comp(o)('a')
If we now make the explicit types implicit again:
const comp = o => R.pipe(
  R.pipe(
    R.prop('foo'),
    R.juxt([R.curry(fn1), R.curry(fn2)])
  )(o),
  R.head
)

comp(o)('a')
Hope that helps @kosmotaur ;).
Of course, you still have one explicit parameter. But making this pointfree is a different discussion!
Marek Stasikowski
@kosmotaur
Aug 03 2017 09:11
@Yord thanks a bunch, that works, and thanks for the tip with making params explicit
Philipp Wille
@Yord
Aug 03 2017 09:11
@kosmotaur You are very welcome :). Have fun!
Marek Stasikowski
@kosmotaur
Aug 03 2017 09:11
:beers:
Marek Stasikowski
@kosmotaur
Aug 03 2017 09:18
sorry but now my appetite for point-free peaked :sweat_smile: do you have any tips here?
Philipp Wille
@Yord
Aug 03 2017 09:22
tbh it did not let me go either and I am still in the repl, figuring it out :p. Though not really sure how to proceed here, yet. Currently toying around with ap, lift, useWith, and converge
Marek Stasikowski
@kosmotaur
Aug 03 2017 09:23
a healthy bit of obsession is always healthy :laughing:
Philipp Wille
@Yord
Aug 03 2017 09:38
Ok, wow, that was harder than I thought!
Syaiful Bahri
@syaiful6
Aug 03 2017 09:38
Generally, if your function have more than 1 arity, and you want to compose them, you can't make it completely point free. In case like your, in my opinion, i will just write the argument explicitly. I will just use the point free style if it help the readability, especially in language like JS.
Philipp Wille
@Yord
Aug 03 2017 09:39
Here is what I came up with:
const obj = {foo: {a:1,b:5}};
const fn1 = (obj, k) => obj[k];
const fn2 = (obj, k) => obj[k] + 5

const comp = pipe(
  useWith(lift(fn1), [ o(of, prop('foo')), of ]),
  head
)

comp(obj, 'a')
Marek Stasikowski
@kosmotaur
Aug 03 2017 09:39
@syaiful6 fair point, if I end up spending another hour on this I'll just curry on, but it's an interesting brain teaser
oh wow
Philipp Wille
@Yord
Aug 03 2017 09:40
Or if you want to keep the currying in comp:
curryN(2, comp4)(obj)('a')
Marek Stasikowski
@kosmotaur
Aug 03 2017 09:41
I don't see fn2 in the comp?
Philipp Wille
@Yord
Aug 03 2017 09:41
(oh I just see I skipped the second function... yeah well)
Philipp Wille
@Yord
Aug 03 2017 10:15
Ok. First off, I agree with @syaiful6 that in this case I would go with the explicit argument.
But just for the sake of discussion, this is a pointfree version:
const comp = R.pipe(
  uncurryN(2, R.pipe(
    R.prop('foo'),
    R.juxt([R.curry(fn1), R.curry(fn2)])
  )),
  head
)

comp(obj, 'a')
Marek Stasikowski
@kosmotaur
Aug 03 2017 10:15
yeah it'd get too cryptic wouldn't it
Philipp Wille
@Yord
Aug 03 2017 10:16
I myself find that too cryptic, yes ;)
I use point free style to make my code more concise. In cases where it doesn't, I usually go with the pragmatic solution even if it has explicit parameters.
Marek Stasikowski
@kosmotaur
Aug 03 2017 10:19
absolutely agree, my team will berate me if I commit that :sweat_smile:
anyway, that was fun, thanks for your support :ok_hand:
Piero Maltese
@pierissimo
Aug 03 2017 11:23

Hi Guys!
I'm new here, I'm playing with ramda but I'm a bit stuck.
In the code, I'd like to manipulate elements of an array inside an object:

const ids = [0, 1];
const fromNode = { ids };
const idToRemove = 1;
const idToAdd = 2;

const removeId = R.compose(R.assoc('ids'), R.reject(R.eq(idToRemove)));
const appendId = R.compose(R.assoc('ids'), R.append(idToAdd));

// that gives the correct output: {"ids": [0, 2]}
const newFromNode = removeId(fromNode.ids)(fromNode)
appendId(newFromNode.ids)(newFromNode)

// that code gives a wrong output: {"ids": [undefined, 2]}
R.compose(appendId, removeId)(fromNode.ids)(fromNode);

What 's the concept I'm missing here?

zernie
@zernie
Aug 03 2017 11:28
Hey guys. How can I refactor this function into a pointfree version?
const f = g =>
R.set(lensA, R.view(lensB, g), g);
Denis Stoyanov
@xgrommx
Aug 03 2017 11:43
Maybe ap
ap(flip(set(lensA)), view(lensB))
Also u need flip
Sorry I'm from phone
Philipp Wille
@Yord
Aug 03 2017 12:36
@zernie How about:
const f = lift(set(lensA))(view(lensB), identity)
Denis Stoyanov
@xgrommx
Aug 03 2017 12:55
Instead of lift and identity u can use ap
zernie
@zernie
Aug 03 2017 13:03
Huh, typescript complains about incompatible types when I try @xgrommx's example
but maybe that's just shortcomings of ramda typings
Thanks @xgrommx, it works! (though there's still problems with typescript)
Denis Stoyanov
@xgrommx
Aug 03 2017 13:20
@zernie I wrote it via my phone) I didn’t check it :smile:
Joey Figaro
@joeyfigaro
Aug 03 2017 18:26
Does anyone have any recommended videos or articles for learning about dealing with null pointer exceptions / unexpected values?
Also, looking for videos/articles on ramda’s placeholder and how it works.
dvc
@diegovdc
Aug 03 2017 19:16
Does anyone know whats the difference between using R.into and a just mapping/filtering?
also, it seems that compose behaves like pipe and viceversa when used inside into, https://goo.gl/VBBdaf
Is that the intended behavior?
Denis Stoyanov
@xgrommx
Aug 03 2017 19:27
Transducers?
Brad Compton (he/him)
@Bradcomp
Aug 03 2017 19:38
@diegovdc into is for transducers, which do a single pass over the list instead of once for each map / filter etc.
As to the 'backwards' behavior, see links in this issue: ramda/ramda#2246
Kurt Milam
@kurtmilam
Aug 03 2017 20:17
I'm trying to add some functions curried with curryN to a prototype object and wondering whether there's a way to correctly bind this.
For example:
Gabe Johnson
@gabejohnson
Aug 03 2017 20:21
@Bradcomp do you use transducers?
Brad Compton (he/him)
@Bradcomp
Aug 03 2017 20:21
There are a few of them in our codebase, but generally not.
It's generally when we have to do a lot of processing on a long list
Gabe Johnson
@gabejohnson
Aug 03 2017 20:22
Seems to me the confusion surrounding their behavior and added complexity to the Ramda implementation suggest they be removed
Kurt Milam
@kurtmilam
Aug 03 2017 20:22
allFnNames.forEach(
  function( fnName ) {
    memberProto[ fnName ] =
      R.curryN( _instanceFnArity( fnName ) )
              ( function( ...ys ) {
                  return allFns[ fnName ]( ...R.append( this, ys ) )
                }
              )
  }
)
I pass memberProto into a constructor function where I use Object.create( memberProto ) to construct an object. I'd like for this to refer to that to-be-constructed object, but I'm afraid it's not possible.
Seems to work fine if I don't wrap the function in curryN.
Brad Compton (he/him)
@Bradcomp
Aug 03 2017 20:27
Yikes! I don't know how I would handle that Kurt
Kurt Milam
@kurtmilam
Aug 03 2017 20:28
I basically have static function definitions that I'd like to also use as instance methods. I've gotten it to work building the methods in the constructor, but not building them ahead of time on the prototype.
@Bradcomp yeah, I'm about ready to give up on putting these methods on the prototype. Possibly a premature optimization, anyway.
Brad Compton (he/him)
@Bradcomp
Aug 03 2017 20:29
@gabejohnson I wouldn't object to their removal