These are chat archives for ramda/ramda

4th
Sep 2015
Jethro Larson
@jethrolarson
Sep 04 2015 02:13
Zu is interesting. Personally I'd try swapping order of nodes and expr on the api
There's something lens-like about this
Martin Algesten
@algesten
Sep 04 2015 06:41
@davidchambers @CrossEye @jethrolarson thanks!!! i'm about to put it into production code at work today. so i'll have it a bit more road tested.
@jethrolarson i have considered that. the order is to do with fnuc. but i want to play nice with the community. so i have a thought that require('zu/inverse') would give me same API but reverse order. i would consider making the default order expr/nodes since i acknowledge i may be the odd one out with fnuc.
Jethro Larson
@jethrolarson
Sep 04 2015 07:45
Not heard of fnuc. I'll check it out
Jethro Larson
@jethrolarson
Sep 04 2015 08:25
Is it a weird irony that it's "func" but jumbled :smile: neat stiff though
Raine Virta
@raine
Sep 04 2015 10:34
@CrossEye I wonder if the @typedef annotation is used correctly. http://usejsdoc.org/tags-typedef.html
Scott Sauyet
@CrossEye
Sep 04 2015 10:56
@raine: it's pretty clearly not used in the way JSDoc would like.
Martin Algesten
@algesten
Sep 04 2015 11:59
@jethrolarson fnuc was me throwing toys out of the pram with ramda argument order. since then however, ramda has gone deep into fantasyland territory and i’m lost. i still use my own lib, but i know i must raise my game and understand why i would want functors, monads, etc.
Alex Schenkman
@alesch
Sep 04 2015 14:20

Hi ramda folks,
I’m new to rambda and I would like to transform this JSON:

{
   ‘2’ : { ‘name': ‘two’},
  ‘1’ : {’name’ : ‘one’}
}

into some sorted iterable (list?) like this:

 [ 
{ id: ‘1’, name: ‘one'},
{ id: ‘2’, name: ’two'}
]

In other words I need to:

  1. Iterate throgh the object entries, and set the id property to its key.
  2. Iterate on that and sort by id.

How can I do this in an elegant way? All my attempts become quite imperative.
Thanks!

Danielle McLean
@00dani
Sep 04 2015 14:32
@alesch Here's one way.
R.pipe(
  R.mapObjIndexed( R.flip( R.assoc('id') )),
  R.values,
  R.sortBy(R.prop('id'))
)
Alex Schenkman
@alesch
Sep 04 2015 14:35
@00Davo Thank you, I’ll read up on those functions.
Scott Sauyet
@CrossEye
Sep 04 2015 14:37
Another: R.converge(R.zipWith(R.assoc('id')), R.keys, R.values). Note that if your ids are actually integers you won't need an additional sort.
Danielle McLean
@00dani
Sep 04 2015 14:43
Oh. Whoops, my version compares the IDs as strings and so won't work if there're multiple digits. :blush: This fixes it, but @CrossEye's version is also correct and shorter so. Yeah.
R.pipe(
  R.mapObjIndexed( R.useWith(R.flip(R.assoc('id')), R.identity, Number)),
  R.values,
  R.sortBy(R.prop('id'))
)
Martin Algesten
@algesten
Sep 04 2015 18:53
every time i reach for R.pipe i feel a bit disappointed with myself...
Alex Schenkman
@alesch
Sep 04 2015 19:03
Thank you @CrossEye. I’ll have to digest that one, :-P
Scott Sauyet
@CrossEye
Sep 04 2015 19:12
@algesten: what's wrong with pipe?
Stefano Vozza
@svozza
Sep 04 2015 19:20
real men use compose :stuck_out_tongue:
Martin Algesten
@algesten
Sep 04 2015 19:30
@CrossEye i use it when i struggle to think functions; when i rather think sequence of operations. it's borderline imperative programming.
your above "converge" was one of those omg-moments for me. it solves a thing i do a R.pipe for every time.
Alex Schenkman
@alesch
Sep 04 2015 19:34

@CrossEye Would you help me understand your suggestion, please?

f = R.assoc('id')
g = R.zipWith( f );
R.converge(g, R.keys, R.values);

I understand that we are partially applying arguments.
assoc takes 3 arguments. The last one is the list itself.
But what happens with the second one?

Martin Algesten
@algesten
Sep 04 2015 19:42
@alesch R.assoc('id') expects two more arguments 1. the value for id and 2. an object to shallow copy and put {id:arg1} into.
R.zipWith with a function that accepts two arguments (1. and 2. above) will then be expecting one array of 1. and one array of 2.
R.keys gives you the array of 1.s and R.values an array of 2.s
Scott Sauyet
@CrossEye
Sep 04 2015 19:47
I guess I'm just a quiche-eater. I love pipe! I feel a little dirty when I have to resort to converge or useWith. I'm glad we have them, but I prefer nice pipelines of functions.
Martin Algesten
@algesten
Sep 04 2015 19:49
hm. ok. if you say so. perhaps i try compose, to see whether backwards feels better ;)
Scott Sauyet
@CrossEye
Sep 04 2015 19:49
Thank you @algesten. I struggle to explain these things succinctly.
Martin Algesten
@algesten
Sep 04 2015 19:49
not sure i managed to. but i wanted to take a stab.
Aldwin Vlasblom
@Avaq
Sep 04 2015 20:00

@alesch I also found CrossEyes answer pretty astounding, so I picked it apart in the REPL. Let's start with converge:

//converge(f, a, b)(x) === f(a(x), b(x))
//so:
R.converge(R.zipWith(R.assoc('id')), R.keys, R.values)(x) //===
R.zipWith(R.assoc('id'))(R.keys(x), R.values(x)) //===
R.zipWith(R.assoc('id'), R.keys(x), R.values(x))

Now R.keys and R.values both produce lists. One containing the ID's (keys) and the other containing objects (values). And as it happens, R.zipWith(f) wants two lists, and it'll pass a pair of items (taken from both lists) into f so that f may produce a single item for the returned list.

In this case we use R.assoc('id') as our f (zipper function), which will receive the ID from the first list, and the object from the second and return a new object on which the "id" property will have been set.

Scott Sauyet
@CrossEye
Sep 04 2015 20:06
An important point here is the parallel between keys and values. They are ordered in parallel. The fourth entry in the list of values is the value of the property of the object at the fourth entry in the list of keys. Without that, this would not work.
Scott Sauyet
@CrossEye
Sep 04 2015 20:19
A version of the same technique where that association is not so important would be R.compose(R.map(R.apply(R.assoc('id'))), R.toPairs). The tradeoff is having to call R.apply. But this might be a little cleaner.
Martin Algesten
@algesten
Sep 04 2015 20:24
well done avoiding R.pipe there ;)
Scott Sauyet
@CrossEye
Sep 04 2015 20:26
Just for you. I wrote it as pipe because that's how I think, and reversed it to compose :smile:
Martin Algesten
@algesten
Sep 04 2015 20:26
haha! :D
just out of curiosity. does Object.keys guarantee an order?
or that multiple invocations will have the same order as a result.
Scott Sauyet
@CrossEye
Sep 04 2015 20:32
Very big point of contention now. #1067.
Scott Sauyet
@CrossEye
Sep 04 2015 20:43
It is not really consisyent with our notion of equals. Two things we think of as equal could have different order of keys. I'm proposing a change, but there's significant opposition.
Martin Algesten
@algesten
Sep 04 2015 20:46
I'm reading. just now at the bit where jdalton appear to be wilfully obtuse regarding the natural order of a list.
Scott Sauyet
@CrossEye
Sep 04 2015 20:50
He's not just trolling, even if it sometimes feels that way. He does have serious points to make. And decisions here are clearly not as obvious to everyone as I would have thought. Lots of smart people with lots of different opinions.
John-David Dalton
@jdalton
Sep 04 2015 21:10
:hear_no_evil:
Martin Algesten
@algesten
Sep 04 2015 21:14
:blush:
Scott Sauyet
@CrossEye
Sep 04 2015 21:15
... and jdalton is one of them :angel:
Raine Virta
@raine
Sep 04 2015 21:22

I think the arrow syntax is a bit too loose

let foo = (a) => ... // ok
let bar = () => ... // ok
let baz = a => ... // ok
let xyz = => ... // not ok

however in case of map(x => x*x) I can understand without parens it's more readable

John-David Dalton
@jdalton
Sep 04 2015 21:23
Arrow funcs are nice
I donno why skinny arrow wasn't done (no lexical bind)
like CS. There was prolly a ton of discussion (as per usual)
Alex Schenkman
@alesch
Sep 04 2015 21:25
@algesten @Avaq @CrossEye Thank you all for the explanations. I’ll have to study them more.
@CrossEye You said you used compose but you thought of it with pipe. How would it be with pipe? In case it becomes easier to read for me.
Scott Sauyet
@CrossEye
Sep 04 2015 21:32
R.pipe(R.toPairs, R.map(R.apply(R.assoc('id')))) -- just reversing the parameter order.
Aldwin Vlasblom
@Avaq
Sep 04 2015 21:33

@alesch pipe is just compose but reversed: pipe(a, b, c) === compose(c, b, a)

I think compose is meant to resemble nested-function calling, like so: compose(a, b, c)(x) looks like a(b(c(x)))

And pipe is meant to resemble piping, like so: pipe(a, b, c)(x) looks like x > a | b | c

Or that's how I think of them anyway. ;)
John-David Dalton
@jdalton
Sep 04 2015 23:03
trying to come up with a better name for useWith and converge. It looks like useWith may be created by way of converge.
naming these things is hhaaaarrrdd grumble grumble
John-David Dalton
@jdalton
Sep 04 2015 23:23
modArgs and distArgs woo
John-David Dalton
@jdalton
Sep 04 2015 23:28
still not great
but betterish
Raine Virta
@raine
Sep 04 2015 23:34
mapArgs
John-David Dalton
@jdalton
Sep 04 2015 23:40
that makes me think of 1 function to map over args
Raine Virta
@raine
Sep 04 2015 23:40
yeah that's true
John-David Dalton
@jdalton
Sep 04 2015 23:41
it could be maybe
converge -> modArgs and useWith -> modPerArg
John-David Dalton
@jdalton
Sep 04 2015 23:54
oh snao
so I created a createModArgs
that takes a resolver
the resolver accepts arg, index, arguments (like value, index, array)
it's used to then create a function that passes the transforms args based on the resolves of the resolver
so for useWith the resolver would be identity and for converge it would be function(value, index, args) { return args }
could be baseModArgs(func, transforms, resolver)