These are chat archives for ramda/ramda

1st
Feb 2016
Richard Seldon
@arcseldon
Feb 01 2016 00:00 UTC
just hoping to get a few key pointers and will then take it from there...
context / thinking behind it, and 10,000 ft design thinking.
boxofrox
@boxofrox
Feb 01 2016 00:00 UTC
quick, huh? have you seen the rich hickey talk on transducers?
Richard Seldon
@arcseldon
Feb 01 2016 00:02 UTC
add ransducer/reduced, value to that list
boxofrox
@boxofrox
Feb 01 2016 00:03 UTC
Richard Seldon
@arcseldon
Feb 01 2016 00:03 UTC
cool. thanks, taking a look.
boxofrox
@boxofrox
Feb 01 2016 00:04 UTC
rich actually breaks down reduce into an abstraction over any iterable, and that becomes transduce.
boxofrox
@boxofrox
Feb 01 2016 00:25 UTC

the @@transducer/init,result/step forms an object referred to as a transformer. The transformer represents a single transformation (map, all, any, drop, take, filter,...) and facilitates chaining many transformers together without creating intermediate collections between each transformer.

reduced, AFAIK, is a kill switch for reduce. when you call reduced(result) in your reducer function, the iterator in reduce sees your result is wrapped in a special object, takes out the result and stops iterating.

I'm not clear about what you referred to as ransducer/value.

Richard Seldon
@arcseldon
Feb 01 2016 00:28 UTC
Good description above @boxofrox thanks. still going through the Hickey talk (strangeloop first) but this all makes sense.
In terms of Ramda implementation and usage of R.transduce(), there are two reducer functions in effect.
the transformer as you call it above.
For that - which Ramda operations (list types) support Transduce atm?
boxofrox
@boxofrox
Feb 01 2016 00:30 UTC
You'd have to search the Ramda API for transduce. Each function that supports transduce mentions it in their descriptions.
Richard Seldon
@arcseldon
Feb 01 2016 00:30 UTC
Is it a specific subset like you listed above - map, all, any, drop, take, filter,.. - or do most of the List oriented functions get this.
Ok, that is actually what I am questioning.
ramda/ramda#1620
Appreciate the input.
boxofrox
@boxofrox
Feb 01 2016 00:34 UTC
I'm probably a bit off on my description of transformer. I think the name stemmed from the idea that a transformer transforms a reducer function.
Richard Seldon
@arcseldon
Feb 01 2016 00:35 UTC
Sure, np, it's all good. I did find the documentation description of Transducer and its accompanying transformer, iterator etc slightly impenetrable.
boxofrox
@boxofrox
Feb 01 2016 00:37 UTC
Yea, it's a bit much to take in without any context.
Richard Seldon
@arcseldon
Feb 01 2016 00:38 UTC
not saying there is an easier way of writing it, but yep, without any context it sort of suggests you have to write functions that adhere to certain interface - this part here - A transformer is an an object that provides a 2-arity reducing iterator function, step, 0-arity initial value function, init, and 1-arity result extraction function, result. The step function is used as the iterator function in reduce. The result function is used to convert the final accumulator into the return type and in most cases is R.identity. The init function can be used to provide an initial accumulator, but is ignored by transduce.
boxofrox
@boxofrox
Feb 01 2016 00:41 UTC
That bit of the docs scared me away from transduce for quite awhile until I saw the example didn't bother writing those functions adhering to a certain interface.
Richard Seldon
@arcseldon
Feb 01 2016 00:44 UTC
Right. and this is the part where I am slightly uncertain about.
as in, which ramda ops are out of the box transformers, and what bootstraps the orchestration internally for transducers.
i get it that there is a specified abstraction interface which provides generic means of unifying streams, observables, channels, lists etc for map, filter like ops.
anyhow, will do some more reading, and spend time going through the code base, looking at the existing tests and documentation, and generally experimenting. cheers.
boxofrox
@boxofrox
Feb 01 2016 00:48 UTC
if you're using R.transduce, it uses its arguments to construct the initial transformer, which is then passed to your iterator function chain compose(map(add(1)), take(2)) where map and take see their data object is a transformer, and each adds another link in the transformer chain and passes it on. Once done, I think R.transduce can start iterating with the final chain of transformers.
the list oriented functions switch to "transducer mode" if their data argument has those @@transducer/init,step,result properties. From there, I have no idea how it works :D
Richard Seldon
@arcseldon
Feb 01 2016 00:50 UTC
This is all really helpful info. thank you.
boxofrox
@boxofrox
Feb 01 2016 00:50 UTC
my pleasure
Richard Seldon
@arcseldon
Feb 01 2016 01:03 UTC
ok, i think it got it at 10,000 ft at least.
So my (limited) understanding of transducers is that they offer composable algorithmic transformation capabilities on lists by being internally used as a reducing function (a function that can be passed to reduce). We also wish to perform all transformations on the first element of the list before moving on to the second element in list etc. Finally, we don't wish to be tied to a particular iterator strategy for the reduction eg. hardcoding something like R.flip(R.append) is no good, we wish to make that a parameter that can be passed in to provide variation in how the iterator deals with results reduction & assembly
(above take 'list' to mean a variety of iterable / list like things)
and the secret sauce, in Ramda code base is _reduce.js
that is where all the conditional checking is going on to know what and how to deal with different types is going on.
transducer points us at using reduce left under the covers rather than say recursion for many ops.
@boxofrox - does that sort of make sense in your understanding?
boxofrox
@boxofrox
Feb 01 2016 01:13 UTC
yep, makes sense.
Richard Seldon
@arcseldon
Feb 01 2016 01:27 UTC
good. an interesting consequence here is that some ops keep state, and internally call that reduced function you were talking about.
see _xtake.js for a good example.
it is counting down on n, and invoking reduced
otherwise calling the next step
boxofrox
@boxofrox
Feb 01 2016 01:29 UTC
which makes sense, you don't want to partially process the 3rd+ element of a collection if your transducer contains a take(2).
Richard Seldon
@arcseldon
Feb 01 2016 01:29 UTC
absolutely.
boxofrox
@boxofrox
Feb 01 2016 01:34 UTC
@arcseldon something for you to tinker with if you want to find which functions act as transducers. http://goo.gl/AysmwC
I think my heuristic for detecting them is accurate.
Or slightly improved http://goo.gl/GF1Pwe
Richard Seldon
@arcseldon
Feb 01 2016 01:38 UTC
nice. just wrapping my head around the _dispatchable.js logic atm
boxofrox
@boxofrox
Feb 01 2016 01:39 UTC
I think of dispatchable as pattern matching in haskell or a switch statement to isolate which use-case to perform.
Richard Seldon
@arcseldon
Feb 01 2016 01:41 UTC
right, yep, it is decision logic. going to have to set up various calls and step through in debugger to really understand but high level think its ok.
David Chambers
@davidchambers
Feb 01 2016 01:45 UTC
Given ['a', 'b', 'c', 'd', 'e'], is there an elegant way to select every second element? ['a', 'c', 'e'] or ['b', 'd'], in this case.
boxofrox
@boxofrox
Feb 01 2016 01:49 UTC
http://goo.gl/L8spMf
const value = ['a', 'b', 'c', 'd', 'e'];

R.pipe(
  R.splitEvery(2),
  R.filter(R.pipe(R.length, R.equals(2))),
  R.map(R.last)
)(value);

//=> ['b', 'd']
David Chambers
@davidchambers
Feb 01 2016 01:50 UTC
Thanks, @boxofrox! I was hoping I'd forgotten about a function which makes this a bit simpler.
boxofrox
@boxofrox
Feb 01 2016 01:50 UTC
I'll dig a bit more
David Chambers
@davidchambers
Feb 01 2016 01:51 UTC
For context, I want to create a lens for every other element of a list, so I can write something like R.over(everyOther, R.map(R.toUpper), ['a', 'b', 'c', 'd', 'e']).
boxofrox
@boxofrox
Feb 01 2016 01:54 UTC
const value = ['a', 'b', 'c', 'd', 'e'];

R.addIndex(R.filter)((a, i) => 0 === i %2, value);

//=> ['a', 'c', 'e']
ooo, lenses.
I understood lenses to be static... hmmm... what if
David Chambers
@davidchambers
Feb 01 2016 02:00 UTC
:warning: Ugly imperative code follows…
const evensLens =
R.lens(list => {
         const result = [];
         for (let idx = 0; idx < list.length; idx += 1) {
           if (idx % 2 === 0) {
             result.push(list[idx]);
           }
         }
         return result;
       },
       (evens, list) => {
         const result = [];
         for (let idx = 0; idx < list.length; idx += 1) {
           if (idx % 2 === 0) {
             result.push(evens[idx / 2]);
           } else {
             result.push(list[idx]);
           }
         }
         return result;
       });

R.over(evensLens, R.map(R.toUpper), ['a', 'b', 'c', 'd', 'e']);
// => ['A', 'b', 'C', 'd', 'E']
boxofrox
@boxofrox
Feb 01 2016 02:13 UTC
I got stuck on an arguments[0] is undefined. http://goo.gl/HN7Ggg
Richard Seldon
@arcseldon
Feb 01 2016 02:27 UTC
just finished the Hickey talk. very good.
@davidchambers , this is really hacky, and hard coded but:
const a = over((lensIndex(0)), R.toUpper);
    const b = over((lensIndex(2)), R.toUpper);
    const c = over((lensIndex(4)), R.toUpper);
    const calc = R.compose(a, b, c);
    expect(calc(value)).to.deep.equal(['A', 'b', 'C', 'd', 'E']);
boxofrox
@boxofrox
Feb 01 2016 02:31 UTC
I think it needs to handle more than just 0, 2, and 4. but you got the idea.
Richard Seldon
@arcseldon
Feb 01 2016 02:31 UTC
right, need some way to codify the above with even indexes to whatever size is required...
like i say it was really the lensIndex and compose options under consideration over the procedural approach. or a mix of both not sure.
barking down the wrong street with that actually.
boxofrox
@boxofrox
Feb 01 2016 02:38 UTC
@davidchambers here ya go. http://goo.gl/yutr5p
const value = ['a', 'b', 'c', 'd', 'e'];

const filterIndex = R.addIndex(R.filter);
const isOdd = (a, i) => 1 === i % 2;
const isEven = R.pipe(isOdd, R.not);

const getter = filterIndex(isOdd);

const setter = (odds, list) => {
  const interleave = (a) => {
    if (isEven(0, a.li)) {
      if (a.li >= list.length) { return false; }
      else                     { return [list[a.li], { li: a.li + 1, oi: a.oi }]; }
    }
    else {
      if (a.oi >= odds.length) { return false; }
      else                     { return [odds[a.oi], { li: a.li + 1, oi: a.oi + 1 }]; }
    }
  };

  return R.unfold(interleave, { li: 0, oi: 0 });
};

const lens = R.lens(getter, setter);

R.over(lens, R.map(R.toUpper), value);

//=> ['a', 'B', 'c', 'D', 'e']
My odds/evens convention is based on the 0-index. Might want to reverse that notation if you're using [ordinal?] (first, second, etc) convention.
Updated that ramtuary link... had toUpper instead of R.toUpper.
Richard Seldon
@arcseldon
Feb 01 2016 02:44 UTC
ah, lensIndex is in Ramda core.
i was using ramda-lens module
and thought i was sneaking something new in.
boxofrox
@boxofrox
Feb 01 2016 02:44 UTC
:)
Richard Seldon
@arcseldon
Feb 01 2016 02:45 UTC
:smile: it is a learning experience today
and the example given does pretty much just what i pasted too.
lol
boxofrox
@boxofrox
Feb 01 2016 02:46 UTC
stick around long enough, you'll see most days are learning experiences for me ;p
Richard Seldon
@arcseldon
Feb 01 2016 02:46 UTC
@boxofrox - is that REPL you are using something you wrote?
boxofrox
@boxofrox
Feb 01 2016 02:46 UTC
i didn't write it. But it is very nice.
Richard Seldon
@arcseldon
Feb 01 2016 02:47 UTC
yep, looks good.
boxofrox
@boxofrox
Feb 01 2016 02:47 UTC
I like his use of emoji in the git commit messages
Richard Seldon
@arcseldon
Feb 01 2016 02:48 UTC
very good
boxofrox
@boxofrox
Feb 01 2016 03:01 UTC
@davidchambers figured out the argument[0] is undefined error. had defined isEven in terms of itself rather than isOdd. http://goo.gl/7u98ux
David Chambers
@davidchambers
Feb 01 2016 03:09 UTC
Thanks for your input, @boxofrox! I had not thought to use R.unfold.
boxofrox
@boxofrox
Feb 01 2016 03:09 UTC
@arcseldon that tranduce-detector doesn't always work. unnest appears to take transformers, but doesn't work properly in that context.
@davidchambers you're welcome :)
boxofrox
@boxofrox
Feb 01 2016 04:40 UTC
awwww yea! mass insert/updates reduced time to insert 73k+ records from over 5hrs to under 1min.
David Chambers
@davidchambers
Feb 01 2016 04:41 UTC
Wow!
boxofrox
@boxofrox
Feb 01 2016 04:50 UTC
I can't help myself. I refactored. http://goo.gl/TysSHw
David Chambers
@davidchambers
Feb 01 2016 04:53 UTC
Could you remove isOdd and isEven? It seems it would be simpler without them.
boxofrox
@boxofrox
Feb 01 2016 04:55 UTC
Indeed! They were only used once apiece. http://goo.gl/KrCHUo
David Chambers
@davidchambers
Feb 01 2016 04:56 UTC
const i = idxs[idx]; is amusing.
boxofrox
@boxofrox
Feb 01 2016 04:57 UTC
list[idxs[idx]] was messing with my OCD :p
That was a fun exercise with lenses. Glad I was around for it. Better crash for the night. Cya tomorrow!
David Chambers
@davidchambers
Feb 01 2016 04:57 UTC
Thanks for your help!
Jethro Larson
@jethrolarson
Feb 01 2016 07:51 UTC
Anyone here spend time with cycle.js?
Robert K. Bell
@r-k-b
Feb 01 2016 07:51 UTC
I'm rassling with it right now
Jethro Larson
@jethrolarson
Feb 01 2016 07:58 UTC
Thanks. I'm just wondering if people here think it's cool.
Robert K. Bell
@r-k-b
Feb 01 2016 08:11 UTC
oh yeah, after cyclejs I get bad feelings from some popular frameworks
Hardy Jones
@joneshf
Feb 01 2016 09:02 UTC
@jethrolarson use it in work
Jethro Larson
@jethrolarson
Feb 01 2016 09:03 UTC
:+1: :-1: ?
Hardy Jones
@joneshf
Feb 01 2016 09:05 UTC
mostly :+1:. Any :-1: is from explaining concepts to people. It's not as straightforward a change as taking on angular or react or something. So it takes more to get people to see the benefit.
Are you deciding between it and other things?
Stepan Kuzmin
@stepankuzmin
Feb 01 2016 12:01 UTC

Hi there! How can I pass JSON.stringify as parameter in R.ifElse?

R.ifElse(R.is(Object), JSON.stringify.bind(JSON), R.identity)({})

This returns function of two arguments, instead of expected "{}"

Raine Virta
@raine
Feb 01 2016 12:03 UTC
R.unary(JSON.stringify)
Stepan Kuzmin
@stepankuzmin
Feb 01 2016 12:05 UTC
Oh, thanks @raine!
Keith Alexander
@kwijibo
Feb 01 2016 12:55 UTC
@stepankuzmin does JSON.stringify need to be bound in some browsers/environments?
Stepan Kuzmin
@stepankuzmin
Feb 01 2016 13:17 UTC
@kwijibo I don’t know
GÁBOR Áron Zsolt
@ashnur
Feb 01 2016 15:25 UTC
when i include ramda with a script tag from cdn, what is the variable name I can use to reach it?
Kibin
@kibin
Feb 01 2016 15:27 UTC
R
@ashnur ^
GÁBOR Áron Zsolt
@ashnur
Feb 01 2016 15:28 UTC
https://github.com/ramda/ramda/blob/master/dist/ramda.js#L8443 i found it, damned jsfiddle tricked me again with the afterbodybeforebody stupid thing
thanks @kibin
Fulton Byrne
@Freyert
Feb 01 2016 15:30 UTC
Why is transduce filed under list? I thought the point of transducers was you are able to iterate over any sort of object by specifying a stepper function?
Keith Alexander
@kwijibo
Feb 01 2016 15:34 UTC
@Freyert I'm not sure what the definition of list is - it could be that Ramda views a list as something that you can iterate over?
Slađan Ristić
@sladiri
Feb 01 2016 16:29 UTC
Is there a way to use mori persistent datastructures with Ramda easily?
Hardy Jones
@joneshf
Feb 01 2016 16:30 UTC
@sladiri do mori data types implement the fantasy-land spec?
Slađan Ristić
@sladiri
Feb 01 2016 16:31 UTC
If I change a nested Object with Ramda it will create a deep copy on change, am I correct? Then it would be nice to use it with an optimized datastructures.
@joneshf I am not sure, but implementing that interface would suffice?
Hardy Jones
@joneshf
Feb 01 2016 16:31 UTC
DEpends on what you're doing withit.
not all of the ramda functions dispatch to fantasyland
Slađan Ristić
@sladiri
Feb 01 2016 16:32 UTC
I see, thanks for the pointer. :)
Keith Alexander
@kwijibo
Feb 01 2016 16:57 UTC
@sladiri fwiw, according to the docs, functions that change objects create shallow copies, only R.clone claims to make a deep copy
have you seen https://medium.com/@drboolean/lenses-with-immutable-js-9bda85674780 ? it's a nice description of how lenses can smooth over the differences in getter/setter APIs
Slađan Ristić
@sladiri
Feb 01 2016 17:00 UTC
@kwijibo Thank you, I am re-reading the docs.
@kwijibo I'll look at this, in our recent project we changed a nested object structure using lenses and R.set()
I wondered if Ramda unconditionally created deep copys to avoid mutations, but the docs explain that.
Slađan Ristić
@sladiri
Feb 01 2016 17:34 UTC
@kwijibo That is a great article with nice examples.
Keith Alexander
@kwijibo
Feb 01 2016 18:08 UTC
yeah, it's nice right
Slađan Ristić
@sladiri
Feb 01 2016 18:11 UTC
the mapped lens doesn't have any documentation it seems.
Slađan Ristić
@sladiri
Feb 01 2016 18:36 UTC
The article uses some mapped lens, but it isn't part of Ramda? "We can use mapped which is also a lens. It acts like map."
Slađan Ristić
@sladiri
Feb 01 2016 18:41 UTC
I see now, it is a separate library built on top of Ramda https://github.com/ramda/ramda-lens/search?utf8=%E2%9C%93&q=mapped
boxofrox
@boxofrox
Feb 01 2016 22:15 UTC

@jethrolarson I spent time with cycle.js a few months back. it's pretty nice from a minimal point of view and the integration with Rx observable was nice to a point. I found it relatively easy to work with when my UI had a fixed number of elements on the page. Anything involving dynamic UI elements that didn't benefit from event delegation (like one or more control panels on a dashboard), and I couldn't wrap my head around how to create the UI elements on the fly and wire them into the Rx observables.

Not to say that it couldn't be done. I went back to React because I needed to make progress. At the time, cycle.js was starting to transition to nested dialogues which weren't well documented. I hope to give cycle.js another try when I find time to tinker again.

kwijibo @kwijibo just finished listening to an interview with @davidchambers I happened across https://www.functionalgeekery.com/episode-31-david-chambers/
Keith Alexander
@kwijibo
Feb 01 2016 22:59 UTC
really good episode
David Chambers
@davidchambers
Feb 01 2016 23:08 UTC
Thanks, @kwijibo. I'm pleased you enjoyed it.