These are chat archives for ramda/ramda

15th
Sep 2016
Jethro Larson
@jethrolarson
Sep 15 2016 04:10 UTC
No opinions? Should I just throw a pr?
Julien Goux
@jgoux
Sep 15 2016 09:09 UTC
I'm not sure I use groupWith correctly
I have an array of objects containing a coordinates key of shape [lat, lng], I want to group the object with the same coordinates
so I did : R.groupWith((a, b) => a.coordinates[0] === b.coordinates[0] && a.coordinates[1] === b.coordinates[1], objects)
but the items with the same coordinates aren't grouped
What am I missing ?
Aldwin Vlasblom
@Avaq
Sep 15 2016 09:17 UTC
@jgoux groupWith creates a group for every sequence of elements that are considered equal: [1, 1, 2, 2, 1, 1] becomes three groups. This was also slightly unintuitive for me: https://gitter.im/ramda/ramda?at=57c7ec5129ee4a670583285b
Julien Goux
@jgoux
Sep 15 2016 09:19 UTC
oh :o
It explains why :D
Aldwin Vlasblom
@Avaq
Sep 15 2016 09:19 UTC
I ended up using something like compose(values, groupBy(x => "${x.coordinates[0]}|${x.coordinates[1]}")), which is totally a hack.
Julien Goux
@jgoux
Sep 15 2016 09:20 UTC
Yes this is what I'd do too xD
Thanks Aldwin ^^
Robin Wenglewski
@rweng
Sep 15 2016 11:14 UTC
Can anyone help me understand #transduce? Is it syntactic sugar, or is there any additional value compared to calling R.reduce(R.flip(R.append), [], transducer(numbers)) (analog to the example in http://ramdajs.com/0.22.1/docs/#transduce)? Also, it states in the docs the first parameter is The transducer function. Receives a transformer and returns a transformer, but it seems to me that it receives the data and returns the transformed data. What am I missing?
Aldwin Vlasblom
@Avaq
Sep 15 2016 12:06 UTC
@rweng Watching the Rich Hickey (inventor of Clojure and transducers) talks about transducers really helped me gain an understanding for them. Here's one: https://www.youtube.com/watch?v=6mTbuzafcII
Robin Wenglewski
@rweng
Sep 15 2016 12:06 UTC
@Avaq Nice, thank you!
Aldwin Vlasblom
@Avaq
Sep 15 2016 12:10 UTC
@rweng In short: reduce underpins every list transformation, but it's a shame that the implementation of reduce has to be re-done for every list-like data structure (like maps, streams, etc). What if we could take the part that is unique for each of these structures, and parameterize it for our "generic reduce"? Now we're halfway to transducers: An abstraction which underpins every iteration-based transformation over every data-structure which can be iterated.
Alastair Hole
@afhole
Sep 15 2016 15:23 UTC
Sorry if you get this one a lot - is there any difference between compose and pipe besides associativity? Is there any compelling reason to choose one over the other beyond style/preference?
Oh, hah well I guess that answers that! return pipe.apply(this, reverse(arguments));
Brad Compton (he/him)
@Bradcomp
Sep 15 2016 15:28 UTC
Yeah, they're totally the same other than argument order
FWIW, I use compose if my composition fits on one line, and pipe if it spans multiple lines
Stefano Vozza
@svozza
Sep 15 2016 15:30 UTC
we're having a bit of a discussion here around the parameter order of R.concat
Brad Compton (he/him)
@Bradcomp
Sep 15 2016 15:31 UTC
Oh no. It's R.gt all over again ;-P
Stefano Vozza
@svozza
Sep 15 2016 15:31 UTC
if it's supposed to be data last, shouldn't R.concat([1,2,3],[4,5,6]) output [4,5,6, 1, 2, 3]?
i know
i think we should break everyone's code on wa whim tbh
i was the last person to touch concat.js so i'm the one getting the blame here
:D
Craig Dallimore
@craigdallimore
Sep 15 2016 15:33 UTC
Oh boy. I was using gt the other day and got utterly surprised.
I can imagine the discussions.
Brad Compton (he/him)
@Bradcomp
Sep 15 2016 15:34 UTC
I think arguments could be made either way depending on your prior intuitions. both arguments to concat are the data
Craig Dallimore
@craigdallimore
Sep 15 2016 15:34 UTC
(I get concat and contains args wrong all the time too)
Brad Compton (he/him)
@Bradcomp
Sep 15 2016 15:35 UTC
contains is the function I use flip on more than any other
I don't know if I am odd in this, but the argument order for concat usually works out well for me. I rarely have to flip it.
Stefano Vozza
@svozza
Sep 15 2016 15:43 UTC
yeah, i've never noticed it before. it's just when i was explaining it a confused coworker new to ramda that it struck me
he was expecting the order to be flipped
Alastair Hole
@afhole
Sep 15 2016 15:51 UTC
@Bradcomp Thanks, sounds like a sensible usage
Eugene Lerman
@airbugg
Sep 15 2016 17:06 UTC
Hi there, this is a pretty abstract and general, though I'm hoping there might be a simple and elegant solution I'm not aware of. Considering an complex object (a cytoscape.js graph representation in JSON), containing two arrays of node and edge objects - I was wondering if there's an elegant way to apply a filter using an arbitrary predicate on the nodes array, and remove any associated edge objects (if edgeSourceId === nodeId || edgeTargetId === nodeId) using a single (composable?) function call (in other words, without having to first explicitly store the new node array and the call another function to filter the edges)
Keith Alexander
@kwijibo
Sep 15 2016 18:24 UTC
@airbugg I can't claim this is particularly elegant, but how about something like:
const edgeHasNode = nodes => 
    ({edgeSourceId, edgeTargetId}) => 
        nodes.some(({nodeId}) => edgeSourceId === nodeId || edgeTargetId === nodeId )

const subGraphByNode = nodePredicate => R.pipe(
  R.evolve({nodes: R.filter(nodePredicate)}), 
  obj => R.evolve({
    edges: R.filter(edgeHasNode(obj.nodes))
  }, obj)
)
ie, evolve the nodes first with your filter predicate, then evolve the edges, applying the filtered nodes from the first step to the filter predicate in the second
Drew
@dtipson
Sep 15 2016 20:31 UTC
@rickmed where did you hear that they are poor performers? I mean, they have some extra overhead compared to a completely bespoke access solution, but they are more generic/expressive
I've been playing with comonads recently, is there any reason why ramda doesn't have a pointfree extend? Seems like it would just be something like this:
const extend = fn => W => {
  return typeof W.extend ==="function" ?
    W.extend(fn) :
    W.map((_,i,arr)=>fn(arr.slice(i)))
};
I suppose there are multiple ways to conceive of the Array fallback, but native Arrays aren't all that interesting as comonads anyhow
Rick Medina
@rickmed
Sep 15 2016 20:33 UTC
@dtipson someone commented that on this channel I just asked why
Drew
@dtipson
Sep 15 2016 20:35 UTC
Imo, it's like the difference between doing const op = compose(fn3, fn2, fn1) vs writing out const op = x => fn3(fn2(fn1(x))) There's some small amount over overhead for using compose, but it's more generic
and the overhead in most cases is pretty small compared to anything else going on in practice.
Rick Medina
@rickmed
Sep 15 2016 20:38 UTC
@dtipson :thumbsup:
Drew
@dtipson
Sep 15 2016 20:39 UTC
though as was recently pointed out to me, compose is something of a special case: it's true that you won't generally compose together 1000s of functions explicitly, but if you use compose in, say, the creation of a transducer, then it's wrapper is going to be run through 1000s of times (I think?) if it's used to process a huge Array. So it ideally should be as performant as possible, given how central and ubiquitous it is to the FP style (and especially the pointfree variant).
Re: extend, searched for it in this room and the repo, but don't see much discussing why it is or is not included (or, for that matter, extract/duplicate)