These are chat archives for ramda/ramda

5th
Feb 2016
Martin Broder
@mrtnbroder
Feb 05 2016 08:50
Happy Friday everyone
Is there a method similar to lodash's merge?
ramda's merge method ignores other key-value pairs within the same object
Raine Virta
@raine
Feb 05 2016 08:52
in other words, you want deep merge
there was going to be, but i don't know if it has moved forward
Martin Broder
@mrtnbroder
Feb 05 2016 08:53
yes :p
wow I see
ramda/ramda#1073
crazy long discussion
Martin Broder
@mrtnbroder
Feb 05 2016 10:38
could someone lead me to an article or something that explains these.... function type definitions (or whatever you call them)
(c → c) → (a,b → a) → a → [b] → a
having a hard time understanding them.
(like, what is c here? is that a general type definition or specific to ramda?)
Aldwin Vlasblom
@Avaq
Feb 05 2016 10:43
@mrtnbroder It's called Hindley-Milner and there's a nice introduction to it in the Mostly Adequate Guide.
Jakub Korzeniowski
@kujon
Feb 05 2016 10:44
+1. the whole book is just the bomb
Martin Broder
@mrtnbroder
Feb 05 2016 10:46
thanks @Avaq !
another question, been fighting with this for a while now
I just can't think of a solution in pure ramda
basically I have an object that has a collection, and I need to find an entry within that collection, change some stuff in it, and return a new copy of the whole object (I don't want to mutate the source)
e.g.
var account = {
  subscriptions: [
    {
      id: 1,
      text: 'foo'
    },
    {
      id: 2,
      text: 'bar'
    },
    ...
  ]
}
Keith Alexander
@kwijibo
Feb 05 2016 10:49
@mrtnbroder have you had a look at R.over ?
Martin Broder
@mrtnbroder
Feb 05 2016 10:50
yeah but I'm not sure its the right one
like, I don't know the index
of the object
I need to find it first with some predicate
Keith Alexander
@kwijibo
Feb 05 2016 10:51
start with writing a function that will find the object you want to change
that's your getter
then use that to compose a setter
then do const myLens = R.lens(getter,setter)
Keith Alexander
@kwijibo
Feb 05 2016 10:56
then you can use R.set(myLens, "new text", account) or R.over to change, eg account.subscriptions[1].text and return a changed copy of account
Martin Broder
@mrtnbroder
Feb 05 2016 10:58
Mhm okay
Lemme try something out
in my case it's a bit more complicated as subscriptions actually have another object with some id which is the actual id I am looking for
var account = {
  subscriptions: [
    {
      id: 1,
      text: 'foo',
      cat: {
        id: 20,
        status: 'good'
      }
    },
    ...
  ]
}
so I am actually looking for id: 20
Keith Alexander
@kwijibo
Feb 05 2016 11:14
@mrtnbroder sorry I've thought about it a bit more, and I'm not sure you can use the getter to compose a setter unless the getter returns a reference to the object, not just a copy
and Ramda functions will always return a copy
sorry to lead you astray
my guess is you have to use something like R.findIndex to create a path to the object you need to change
Martin Broder
@mrtnbroder
Feb 05 2016 11:39
alright!
I have something that is definitely close
any improvement suggestions @kwijibo ?
http://goo.gl/tbYV38
Martin Broder
@mrtnbroder
Feb 05 2016 11:49
wow I just noticed that it replaced the list
[] => {key - value}
that is... bad.
Keith Alexander
@kwijibo
Feb 05 2016 12:20
looks good @mrtnbroder
if you change this bit:
//var lensPath = R.lensPath(['subscriptions', found])
//this thinks everything is an object
var lensPath = R.compose(
  R.lensProp('subscriptions'), R.lensIndex(found)
)
it won't change your arrays into objects
(I was surprised it did that too ... )
Martin Broder
@mrtnbroder
Feb 05 2016 13:30
thanks @kwijibo !
Keith Alexander
@kwijibo
Feb 05 2016 13:34
I think perhaps Ramda's definition of path excludes array indexes
which is a bit sucky
so it just assumes everything it traverses is an object
it's a shame because otherwise, you wouldn't need lenses, and could have just used R.assocPath
Jakub Korzeniowski
@kujon
Feb 05 2016 14:18
@mrtnbroder http://goo.gl/gcz06f
Keith Alexander
@kwijibo
Feb 05 2016 14:20
@kujon nice
Jakub Korzeniowski
@kujon
Feb 05 2016 14:21
or actually http://goo.gl/vEPOaD because you want to replace whole subscription

question: how to turn this:

// l :: Lens Account Animal
var l = R.compose(R.lensProp('subscriptions'), createSubscriptionLens(201, account), R.lensProp('animal'));

Into a function createAnimalLens :: Int -> Account -> Lens Account Animal?

*point-free
Martin Broder
@mrtnbroder
Feb 05 2016 14:36
good question
Jakub Korzeniowski
@kujon
Feb 05 2016 14:39
I've got weird ideas about combining R.compose and R.apply like:
var createAnimalLens = R.pipe(
  createSubscriptionLens,
  R.of, 
  R.prepend(R.lensProp('subscriptions')),
  R.append(R.lensProp('animal')),
  R.apply(R.compose)
);
but it's an overkill and also impossible to decipher
Keith Alexander
@kwijibo
Feb 05 2016 14:48
:)
times like this, arrow functions seem like a nice solution
i think of it just like templating arguments into a composition
Martin Broder
@mrtnbroder
Feb 05 2016 14:53
when I could just pass (id, replacement, account) to some function
and get the 'new' account with the replaced animal
Jakub Korzeniowski
@kujon
Feb 05 2016 14:53
@kwijibo I feel the same :smile: Just wanted to do it point-free as an exercise
Martin Broder
@mrtnbroder
Feb 05 2016 14:53
that would be awesome
Keith Alexander
@kwijibo
Feb 05 2016 14:55
@kujon I waver between thinking there are definite limits to point-free, and wondering if all you need are some more helper functions
Jakub Korzeniowski
@kujon
Feb 05 2016 14:58
@mrtnbroder http://goo.gl/KYUjvZ
Keith Alexander
@kwijibo
Feb 05 2016 15:00
const pipe3 = (before, func, after) => ...funcArgs => R.pipe(before, R.partial(func, ...funcArgs), after)
Martin Broder
@mrtnbroder
Feb 05 2016 15:02
awesomesauce
thanks guys! Now I just need to learn more about types :)
Keith Alexander
@kwijibo
Feb 05 2016 15:05
const createAnimalAccount = pipe3(
   R.lensProp('animal')
 , createSubscriptionLens
 , R.lensProp('subscriptions')
)
(or something like that)
Jakub Korzeniowski
@kujon
Feb 05 2016 15:06
or actually: I'd rewrite my solution to operate on [Subscription] instead of Account. and as a very last step I'd wrap it in R.lensProp('subscriptions'). That'd decouple it from Account.
Keith Alexander
@kwijibo
Feb 05 2016 15:06
yeah, good call
Martin Broder
@mrtnbroder
Feb 05 2016 15:22
do you guys think this whole operation could also be achieved with R.transduce?
Brett
@bberry6
Feb 05 2016 15:23
Hey there, Ramda noob here. I was reading the docs and im not sure how to use R.comparator. The example is var cmp = R.comparator((a,b) => a.age < b.age); var ppl = [...]; R.sort(cmp, ppl);. Why not write the function directly like var cmp = (a,b) => a.age < b.age; var ppl = [...]; R.sort(cmp, ppl);
Keith Alexander
@kwijibo
Feb 05 2016 15:24
@mrtnbroder I don't see howR.transduce fits in here? it's more for combining mappers, filterers, reducers, etc without having to loop multiple times isn't it?
@bberry6 R.sort takes a function that returns a negative number, zero, or a positive number
Martin Broder
@mrtnbroder
Feb 05 2016 15:28
it sounded like it as it accepts a transformer and returns a single item
anyway
Brett
@bberry6
Feb 05 2016 15:28
@kwijibo ahhh okay, thanks!
Keith Alexander
@kwijibo
Feb 05 2016 15:29
R.comparator is when you want to convert a function that returns a boolean, so that you can use it with R.sort
Brett
@bberry6
Feb 05 2016 15:29
yeah, that makes sense. Are there other Ramda functions that take functions that return -1, 0, +1
?
Keith Alexander
@kwijibo
Feb 05 2016 15:30
@bberry6 not as far as I can tell
Brett
@bberry6
Feb 05 2016 15:33
@kwijibo great ty
Keith Alexander
@kwijibo
Feb 05 2016 15:35
np
Drew
@dtipson
Feb 05 2016 16:00
@jackfirth I think my concern is really just mostly that if people first learning about them hear that "lenses/transversals compose backwards" they can get a weird/confusing sense of what's going on that delays understanding. Maybe I'm just speaking for my own case.
I think it's easier to think about with simple transducers, because it's even clearer there that what you're passing through the composition is a function, not a value, and so when the resulting function is run, the outermost/leftmost function runs and as part of doing so uses the innermost/rightmost function.
compose( f => v => !console.log('f') && f(v), g => v => !console.log('g') && g(v))(x=>x+1)(5);//-> logs "f", "g", returns 6
There's probably just a better way to explain it I'm not thinking of that makes it clearer faster, just in my own experience hearing "compose backwards" delayed understanding it
Tobias Pflug
@gilligan
Feb 05 2016 18:33
@scott-christopher not around, are you ?
@davidchambers @CrossEye are you guys around ?
or just anyone else who has a good understanding of @scott-christopher 's profunctor lens PR
Brett
@bberry6
Feb 05 2016 18:43
Not sure if this is the best place to ask this question, but if i have something like var list = [{foo: {bar: 1}}, {foo: {qux: 2}}, {foo: {bar:3}}]; and i want to extract an array like [1,2] where its just the foo.bar values of the objects with foo.bar. I was thinking of doing a filter first to get the objects with foo.bar and then a map to extract the values
i saw someone mentioning transduce, is this a case where that may be useful?
Scott Sauyet
@CrossEye
Feb 05 2016 19:19
@gilligan I'm around briefly, but can't say I've grasped that impl yet.
Tobias Pflug
@gilligan
Feb 05 2016 19:25
@CrossEye i am not even at the point where I want to grasp the implementation - Apparently I am still having problems using some of the exposed functions
@CrossEye L.over(R.compose(L.mapped, xLens), R.inc, [{x:1}]) // => [ { x: { x: 1 } } ]
@CrossEye bit confused about that
Scott Sauyet
@CrossEye
Feb 05 2016 19:28
You're further along than I am. I've only looked, not even tried yet, I'm afraid.
Tobias Pflug
@gilligan
Feb 05 2016 19:28
@CrossEye too bad - I was hoping for you to point me at some obvious mistake hehe
Scott Sauyet
@CrossEye
Feb 05 2016 19:29
Sorry, maybe after the weekend. :smile:
Tobias Pflug
@gilligan
Feb 05 2016 19:32
;-}
I started an attempt at documenting the API but haven't gotten very far (https://github.com/gilligan/ramda-lens/tree/pf-documentation)
Tobias Pflug
@gilligan
Feb 05 2016 19:49
hm.. is R.over(R.compose(R.map, xLens), R.inc, [{x:1}]) supposed to work ?
ah, no.
Brad Compton (he/him)
@Bradcomp
Feb 05 2016 19:57
@bberry6 Do you mean something like this?
var list = [{foo: {bar: 1}}, {foo: {qux: 2}}, {foo: {bar:3}}];

let happyPath = R.path(['foo', 'bar']);
let transducer = R.compose(R.filter(happyPath), R.map(happyPath))
R.transduce(transducer, R.flip(R.append), [])(list)   //[1, 3]
Martin Broder
@mrtnbroder
Feb 05 2016 19:58
humm
why not simply
var list = [{foo: {bar: 1}}, {foo: {qux: 2}}, {foo: {bar:3}}];

let happyPath = R.path(['foo', 'bar']);
let transducer = R.pipe(R.filter(happyPath), R.map(happyPath))
transducer(list)
Brad Compton (he/him)
@Bradcomp
Feb 05 2016 19:59
@mrtnbroder That will work, but I believe it will make two passes over the data
one for the filter and one for the map
Martin Broder
@mrtnbroder
Feb 05 2016 20:05
the test setup may be complete crap
may need to iterate over more data
Kevin Wallace
@kedashoe
Feb 05 2016 20:07
you are not likely to see any performance improvements using transducers with such a small amount of data
Martin Broder
@mrtnbroder
Feb 05 2016 20:08
like I said ;)
Kevin Wallace
@kedashoe
Feb 05 2016 20:09
@Bradcomp you can also use into
var list = [{foo: {bar: 1}}, {foo: {qux: 2}}, {foo: {bar:3}}];

let happyPath = R.path(['foo', 'bar']);
R.into([], R.compose(R.filter(happyPath), R.map(happyPath)), list);
you can also use chain to do it all in one pass
var list = [{foo: {bar: 1}}, {foo: {qux: 2}}, {foo: {bar:3}}];
R.chain(R.pipe(R.path(['foo', 'bar']), R.when(R.isNil, R.always([]))), list);
Brad Compton (he/him)
@Bradcomp
Feb 05 2016 20:35
@kedashoe I forgot about into! Definitely simplifies things.