These are chat archives for ramda/ramda

6th
Sep 2016
Matt Stewart
@mattste
Sep 06 2016 00:04
Doing transformations like this is such a common thing, I feel like there has to be a clean functional answer to this that I just don’t know about.
Scott Christopher
@scott-christopher
Sep 06 2016 00:24
You can kinda think of lenses as only being able to target something that exists, so you can't use them directly to generate the missing { userInfo: { local: _ } } part.
Matt Stewart
@mattste
Sep 06 2016 00:25
@scott-christopher That helps. Any suggestions on how to solve my problem? (with lenses, something else or a combination)
Scott Christopher
@scott-christopher
Sep 06 2016 00:25
There is however R.assocPath that can be used to generate the surrounding structure even if it doesn't exist on the target
@ram-bot
assocPath(['userInfo', 'local'], { firstName: 'Scott' }, {})
ram-bot
@ram-bot
Sep 06 2016 00:25
{ userInfo: { local: { firstName: 'Scott' } } }
Scott Christopher
@scott-christopher
Sep 06 2016 00:26
So you could compose R.over and R.assocPath together to achieve something close to your example.
Matt Stewart
@mattste
Sep 06 2016 00:27
Now that sounds interesting.
Scott Christopher
@scott-christopher
Sep 06 2016 00:30
Depending on exactly what you're, you could avoid lenses alltogether.
@ram-bot
const upperName =
  compose(name => assocPath(['userInfo', 'local', 'firstName'], name, {}), toUpper)
upperName('Scott')
ram-bot
@ram-bot
Sep 06 2016 00:30
{ userInfo: { local: { firstName: 'SCOTT' } } }
Matt Stewart
@mattste
Sep 06 2016 00:32
I figure the lenses will come in handy since I’ll be accessing this deeply nested data often and having multiple functions run that need access to it. Might as well create all of them (although it seems like a lot of upfront work).
Scott Christopher
@scott-christopher
Sep 06 2016 00:46
I think I've got an example of a non-law-abiding partial lensProp for acheiving something similar to what you want. I'll see if I can dig it up and get back to you.
Matt Stewart
@mattste
Sep 06 2016 00:47
That would be awesome. Thanks @scott-christopher
Churchill Lee
@FeliciousX
Sep 06 2016 01:56
@JAForbes i thought it's R.ap( fns, [ x ] )
Scott Christopher
@scott-christopher
Sep 06 2016 01:56
@mattste
const partialLensProp = p => R.lens(
  R.ifElse(x => x === void 0, R.identity, R.prop(p)),
  (v, obj) => R.isNil(obj) ? R.objOf(p, v) : R.assoc(p, v, obj)
);

const abLens = R.compose(partialLensProp("a"), partialLensProp("b"));
const abcBar = { a: { b: { c: "bar" }}};

R.view(abLens, {});
//=> undefined
R.view(abLens, abcBar);
//=> { c: 'bar' }
R.over(abLens, R.assoc("foo", "val"), {});
//=> { a: { b: { foo: 'val' } } }
R.over(abLens, R.assoc("foo", "val"), abcBar);
//=> { a: { b: { c: 'bar', foo: 'val' } } }
James Forbes
@JAForbes
Sep 06 2016 02:37
@FeliciousX it is, my mistake
Scott Christopher
@scott-christopher
Sep 06 2016 04:19
@mattste Translating that to your original example:
const lensPropP = p => R.lens(
  R.ifElse(x => x === void 0, R.identity, R.prop(p)),
  (v, obj) => R.isNil(obj) ? R.objOf(p, v) : R.assoc(p, v, obj)
);

const localUserInfoL = R.compose(lensPropP('userInfo'), lensPropP('local'))
const firstNameL = R.compose(localUserInfoL, lensPropP('firstName'));

const setFirstName = R.set(firstNameL)
const updateFirstName = R.over(firstNameL)
const getFirstName = R.view(firstNameL)

const scott = setFirstName('Scott', {})
console.log(scott)
//=> {"userInfo": {"local": {"firstName": "Scott"}}}

const name = getFirstName(scott)
console.log(name)
//=> "Scott"

const scottShout = updateFirstName(R.toUpper, scott)
console.log(scottShout)
//=> {"userInfo": {"local": {"firstName": "SCOTT"}}}

const newName = setFirstName('Bob', scott);
console.log(newName)
//=> {"userInfo": {"local": {"firstName": "Bob"}}}
Martin Broder
@mrtnbroder
Sep 06 2016 09:51
Hey @davidchambers , where did you generate the S logo in the readme? :D
Syaiful Bahri
@syaiful6
Sep 06 2016 09:51
@scott-christopher oh, i dont know that, maybe because Rambda docs doesn't mention it..
David Chambers
@davidchambers
Sep 06 2016 11:42
@mrtnbroder, see sanctuary-js/sanctuary-logo.
Martin Broder
@mrtnbroder
Sep 06 2016 12:00
I was talking about this:
/*    #######
   ####     ####
 ####   ###   ####
#####   ###########   sanctuary
########   ########   noun
###########   #####   1 [ mass noun ] refuge from unsafe JavaScript
 ####   ###   ####
   ####     ####
      #######    */
or did you do it by hand?
Matt Stewart
@mattste
Sep 06 2016 13:18
@scott-christopher that is awesome. Thank you!
David Chambers
@davidchambers
Sep 06 2016 14:32
Oh, that one I did by hand, @mrtnbroder.
Kurt Milam
@kurtmilam
Sep 06 2016 16:50
Is there a nicer way to do this:
obj[propName] = obj[propName] || {}
Not that it matters for the question, but obj is an accumulator inside a reduce, so I'm not trying to mutate objects willy-nilly :)
LeonineKing1199
@LeonineKing1199
Sep 06 2016 16:55
Well, passing an object is passing a reference so obj[propName] = 'abc' is definitly a mutation
Kurt Milam
@kurtmilam
Sep 06 2016 16:59
I was under the impression that it was 'ok' to mutate an accumulator object inside a reduce.
Brad Compton (he/him)
@Bradcomp
Sep 06 2016 17:00
@kurtmilam
const defaults = { propName: {} };

obj = R.merge(defaults, obj);
This has the added benefit of being able to set multiple defaults at once
Kurt Milam
@kurtmilam
Sep 06 2016 17:02
@Bradcomp
that looks good, thanks. I"ll give it a go in my slightly more complicated code shortly.
Travis LaDuke
@laduke
Sep 06 2016 17:42
I have something like const filterByProp = R.filter(R.propEq(somePropName, somePropValue)); but now I needsomePropValue to sometimes be an array of strings and sometimes just be a string. Can I rewrite it a little so it works either way?
LeonineKing1199
@LeonineKing1199
Sep 06 2016 17:52
I think there's R.either which may help
Brad Compton (he/him)
@Bradcomp
Sep 06 2016 17:59
You could write the function that takes the array of values, and then use something to coerce the string input like R.when(R.is(String), R.of)
Travis LaDuke
@laduke
Sep 06 2016 18:01
Gonna need an Any too
Maybe just make it always be an array :)
Travis LaDuke
@laduke
Sep 06 2016 19:49
can't even figure it out for array :(
I need var hasBrowHair = R.propEq('hair', ['brown','red']);
Brad Compton (he/him)
@Bradcomp
Sep 06 2016 19:56
@laduke Check out
R.where
Brad Compton (he/him)
@Bradcomp
Sep 06 2016 19:57
R.where({hair: R.contains(R.__, ['brown', 'red'])})
Travis LaDuke
@laduke
Sep 06 2016 19:58
i could contains.. yeah
thank you for answering me twice.
Travis LaDuke
@laduke
Sep 06 2016 21:56
What's a functional way to toggle something into/outof a list?
toggle('c', ['a','b']) //=> ['a','b','c']
toggle('c', ['a','b','c']) //=> ['a','b']
declarative*
Travis LaDuke
@laduke
Sep 06 2016 22:21
  var x = R.ifElse(
    R.contains(name),
    R.without(name),
    R.prepend(name)
  );
I need to curry that differently
oh wow it works
Travis LaDuke
@laduke
Sep 06 2016 22:27
  var toggleItemInList = R.ifElse(
    R.contains,
    R.without,
    R.prepend
  );

toggleItemInList(name, list)
O_O
LeonineKing1199
@LeonineKing1199
Sep 06 2016 22:33
Ha, that's funny.
It's because ifElse operates on variadics and just does simple argument forwarding
So that's why that works.
I'd recommend keeping it the first way unless there's a good reason to use the second way. With the second one, it'd be easy to just create a bunch of partially applied functions instead. What happens if you call the second one as toggleItemInList(name)?
I'm assuming it'd create some weird function
Travis LaDuke
@laduke
Sep 06 2016 22:49
toggleItemInList(name)(list) works somehow. o_O
Brad Compton (he/him)
@Bradcomp
Sep 06 2016 22:52
ifElse is curried to the max length of the functions passed into it
* the result of ifElse I mean