These are chat archives for ramda/ramda

31st
Mar 2017
Rónán
@ronanyeah
Mar 31 2017 08:11
@rickmed personally I think it's more readable/less noisy
Denis Stoyanov
@xgrommx
Mar 31 2017 08:12
@jonahx if u want enum - use typescript
Alastair Hole
@afhole
Mar 31 2017 10:18
set is curried, right?
Kurt Milam
@kurtmilam
Mar 31 2017 10:20
@afhole yes
Alastair Hole
@afhole
Mar 31 2017 10:21
I'm struggling with this const updateWidget = prop => value => set(compose(lensProp('widget'), immLens(prop)), value); - if I factor out value then it breaks and I'm not sure why
Maybe it's the way I'm calling it...
Hmm I'm using it to map a stream so maybe it's being given extra params
A real gotcha
Kurt Milam
@kurtmilam
Mar 31 2017 10:23
Is value a stream?
And how is it breaking if you factor out value?
Alastair Hole
@afhole
Mar 31 2017 10:25
e.g. name$.map( updateWidget('name') ) I think I know what's happening - it must be being called with three params by map instead of just applying it with a value, annoying
Maybe pointful with value is the best way
Kurt Milam
@kurtmilam
Mar 31 2017 10:25
Which stream implementation are you using?
Alastair Hole
@afhole
Mar 31 2017 10:25
RxJS 4
Map passes value/index/observable
Kurt Milam
@kurtmilam
Mar 31 2017 10:26
I'm using flyd atm, and am also playing with operating on stream contents using lenses.
That's a shame.
Alastair Hole
@afhole
Mar 31 2017 10:26
Yeah it's caught me out a couple of times so far
It's been masked by composing with prop which happily ignores the extra params
Just like array map I suppose
Kurt Milam
@kurtmilam
Mar 31 2017 10:27
It would be annoying to be stuck with a library whose map implementation is 'broken'.
Alastair Hole
@afhole
Mar 31 2017 10:28
Be nice if there was a different operator for just the value
Presumably they just aped array map
Kurt Milam
@kurtmilam
Mar 31 2017 10:28
It would be nice if map just passed in the value. Then you could add mapIndexed and mapIndexedWithObservable for people who thought they needed it.
Yeah, I think Array.map is sort of broken in that respect.
Alastair Hole
@afhole
Mar 31 2017 10:29
Yep, can't think of a single time I've ever cared about the index or the observable - probably both good indicators that you've done something wrong
I can't think of a better solution than pointful with value
Kurt Milam
@kurtmilam
Mar 31 2017 10:30
I used the index and array way back before I knew better. They were there to be used, so I figured it made sense to try to use them.
I don't use them any more.
identity( 1, 2 ) returns 1, so you might be able to use that to filter out the unnecessary values.
You might also have more luck using R.map rather than rxjs.map.
Alastair Hole
@afhole
Mar 31 2017 10:38
Good ideas, thanks - will have a think
Only learnt the other day that R.map works on objects, haven't used it for good or evil yet though
Kurt Milam
@kurtmilam
Mar 31 2017 10:41
As I mentioned above, I've been playing with streams and lenses lately. flyd stream$.map( fn ) seems to be well behaved, but I've also used R.map( fn )( stream$ ) interchangeably.
Alastair Hole
@afhole
Mar 31 2017 10:42
Composing with identity works nicely but pointful reads better, will try R.map
We're fairly heavily tied to RxJS 4 for the foreseeable
mostjs is well done I think if you're looking for something functional - I think it's supports Fantasy Land
Bugger, R.map just dispatched to Observable.prototype.map
Ah well, pointful it is. At least I understand how it breaks now - thanks for your help :)
Kurt Milam
@kurtmilam
Mar 31 2017 10:47
:thumbsup: I started looking at mostjs in earnest last night. flyd complies to the fantasy land applicative specification, as well.
Alastair Hole
@afhole
Mar 31 2017 10:48
They make a point of how fast most is, don't know how much difference that makes in practice
Kurt Milam
@kurtmilam
Mar 31 2017 10:48
I like the fact that mostjs seems super fast. It would be interesting to know how flyd compares
:thumbsup: same page :D
Alastair Hole
@afhole
Mar 31 2017 10:48
hehe
I don't know what you have to do to notice performance with streams, obviously more than we are doing with RxJS
Kurt Milam
@kurtmilam
Mar 31 2017 10:49
In the app I'm currently working on, there will be a need for speed when dragging and dropping SVG elements.
Alastair Hole
@afhole
Mar 31 2017 10:49
Rx and Immutable are great but the method-based API is such a PITA
Also I would kill for a composition operator in JS :)
Kurt Milam
@kurtmilam
Mar 31 2017 10:50
The app contains a sort of 'drafting' component that allows the user to drag elements around a plan.
So I'm thinking that could be an interesting test of stream performance.
Alastair Hole
@afhole
Mar 31 2017 10:50
Be very interesting to see how noticeable the performance differences are
I'm quite a skeptic when it comes to performance for better or worse, maybe I should play more PC games
Kurt Milam
@kurtmilam
Mar 31 2017 10:51
Indeed. I wrote the original app 7 years ago using jQuery and underscore. A bunch of unmaintainable spaghetti code.
But I noticed performance issues with drag and drop using libraries, so I whipped up the best-performing example I could imagine, and the differences were noticeable.
Alastair Hole
@afhole
Mar 31 2017 10:54
Very happy with lenses though (inspired by https://medium.com/@drboolean/lenses-with-immutable-js-9bda85674780)
Even if I still can't wrap my head around why they are left-to-right
Kurt Milam
@kurtmilam
Mar 31 2017 11:16
That tripped me up at first, too. This reddit post on lens composition in haskell might be helpful.
Alastair Hole
@afhole
Mar 31 2017 11:37
Haha yeah I've read that reddit post... Might need to read it again ;)
Although I was struggling to work out how to add some error handling with lenses
e.g. handling a non-existent key
It throws before I have a chance to catch it
Bravi
@Bravilogy
Mar 31 2017 12:12
how can I transform an array to object?
['hello', 'world'] -> { 0: 'hello', 1: 'world' }
smth like that?
ah nvm, mapObjIndexed(identity) does it
Jonah
@jonahx
Mar 31 2017 13:54
@xgrommx I actually started that route, but bringing typescript into my whole project started getting painful — eg, integrating with ramda has some missing features (__, and some currying situations), plus it made the build process more complex (this one wasn’t a big deal). so if all i really need is enums, it doesn’t seem worth it to me. and if i’m not going to integrate TS but only use it to generate my enum code, that also doesn’t seem worth it when I can just create a utility to function to do the same. i also realized i wanted my enums to have custom capabilities. i ended up making a utility function that allow me to use a private constructor to create a fixed list of objects, while using Symbol.hasInstance to make each of those objects have the enum type:
const Enum = (ctor, keys) => {
  const create = is(Array, keys[0]) ?
    x => [x[0], new ctor(...x)] :
    x => [x, new ctor(x)];
  const ret = pipe(map(x => create(x)), fromPairs)(keys);
  ret[Symbol.hasInstance] = is(ctor);
  return ret;
};

const Action = Enum(
  function Action(letter, description) {
    this.letter = letter;
    this.toString = always(description);
  }, [
    ['R', 'raise'],
    ['C', 'call'],
    ['F', 'fold']
  ]
);
krzysztofpniak
@krzysztofpniak
Mar 31 2017 14:23

Hi,
I'm wondering how can I achieve something similar to let notation from haskell language. I mean compute result and use it in the same expression. ie(pseudo language):

let x = y * y in someFunction(x) + someOtherFunction(x)

In general I'm looking for something that will help me avoid repetitions like:

const result = someFunction(y * y) + someOtherFunction(y * y)

Or multi expression like this:

const yy = y * y;
const result = someFunction(yy) + someOtherFunction(yy)

After short consideration I think it should look like:

letIn({yy: y * y}, {yy} => someFunction(yy) + someOtherFunction(yy));

Is there something like this available in Ramda?

Jonah
@jonahx
Mar 31 2017 14:28
@krzysztofpniak
converge(add, someFunction, someOtherFunction)(y*y)
Jonah
@jonahx
Mar 31 2017 14:33
The y*y part reminds me of another question, which I’ve been meaning to ask here. Does ramda have a “reflexive” operator? Meaning, given a binary function f, reflexive(f) should return a unary function which takes a single argument arg and returns f(arg, arg). Eg:
const square = reflexive(multiply)
krzysztofpniak
@krzysztofpniak
Mar 31 2017 14:42
@jonahx thanks, looks like something I was looking for
Gabe Johnson
@gabejohnson
Mar 31 2017 14:45
@krzysztofpniak
((y, x=y*y) => someFunction(x) + someOtherFunction(x))(5)
or if you already have a y,
((x=y*y) => someFunction(x) + someOtherFunction(x))()
Jonah
@jonahx
Mar 31 2017 14:47
@gabejohnson that’s a neat trick, but conceptually doesn’t it boil down to a different (albeit more compact) syntax for creating an intermediate variable (what @krzysztofpniak called a multi-expression in his examples above)
Raine Virta
@raine
Mar 31 2017 14:48
@ram-bot ((x, y = x + 1) => y)(1)
ram-bot
@ram-bot
Mar 31 2017 14:48
2
Gabe Johnson
@gabejohnson
Mar 31 2017 14:50
@jonahx I would argue (because I like to :smile:) that my example is nearly identical to the pseudo code @krzysztofpniak wrote in the OP
Jonah
@jonahx
Mar 31 2017 14:52
@gabejohnson right, that’s what i meant. so it retains the original’s problem (assuming you see it as such) of not being point-free.
Robert Mennell
@skatcat31
Mar 31 2017 14:53
@gabejohnson it also comes with the added benefit of only 2 pointers instead of 3, but I'm sure that overhead is pretty much worthless to think about. It also doesn't evaluate until execution meaning you get more functional paradigms such as
const lazyApplicable = fno => fni => (x, y = fni(x)) => fno(y)
which you can see almost immeadiate value in I'm guessing, but mainly for just readability
const lazyApplicable = fo => fi => x => fo(fi(x))
Robert Mennell
@skatcat31
Mar 31 2017 14:58
oh god I missed a chance for a pun!
krzysztofpniak
@krzysztofpniak
Mar 31 2017 14:58
@jonahx from my perspective trick written by @gabejohnson its not multi expression because it still allows me to use it in lambda without brackets, semicolons and return.
Gabe Johnson
@gabejohnson
Mar 31 2017 15:01
I'm assuming (usually a bad idea) that the let expression would be nested within other expressions and that's it's a one-off
László Vadász
@maxinteger
Mar 31 2017 15:11
I know with in JS like goto in other languages, but
const x = 1
with({x, y: x+x}) console.log(y, x)
Jonah
@jonahx
Mar 31 2017 15:13
@krzysztofpniak true, the syntax is different (and i agree better). but you still have an extra “point” — ie, a name that serves no purpose other than to hold the result of an intermediate calculation. it sounds like that isn’t the part that was bugging you, and rather it was the verboseness you didn’t like. in which case @gabejohnson’s solution solves your problem perfectly.
Rick Medina
@rickmed
Mar 31 2017 15:17
I've seen a few times the let in question around here...do you guys find it that painful to just use an intermediary let/const? or is there something I'm missing?
krzysztofpniak
@krzysztofpniak
Mar 31 2017 15:19
@rickmed yes, its painful when almost all of the code is written as single expressions, without brackets and return statements.
Jonah
@jonahx
Mar 31 2017 15:21
@rickmed yeah, it’s essentially boilerplate. it bothers me for the same reason it bothers me any time a language or library forces me to do something that isn’t logically needed.
Rick Medina
@rickmed
Mar 31 2017 15:23
@krzysztofpniak isn't that an argument to my point? why introduce quirky tricks or syntactic functions when you only need intermediary vars here and there?
@jonahx would you use intermediary vars that much to consider it boilerplate?
(I like let expressions in langs that support them)
Jonah
@jonahx
Mar 31 2017 15:27
@rickmed it’s not a matter of how much, it’s that anytime i ever have to use them when i don’t want to use them it bugs me a little. btw, i’m not saying i never use them. sometimes naming an intermediary concept helps clarity. but in those cases i want to use them. vs a case like @krzysztofpniak’s original question where you don’t want them, but you literally cannot figure out how to syntactically write your expression without them.
Rick Medina
@rickmed
Mar 31 2017 15:29
@jonahx I'm just curious since is the same case about point free. Too many times I've seen code obsessively trying to write it in point free style while badly hurting readability (which is 10x more important imo)
Jonah
@jonahx
Mar 31 2017 15:31
@rickmed agree 100%. sometimes the cure is worse than the disease. and sometimes the disease isn’t a disease but a compact and readable way to write something. i’m not a point-free nazi, but as a general rule point-free code is more readable.
Rick Medina
@rickmed
Mar 31 2017 15:34

I have no idea about @krzysztofpniak specific case but I wouldn't understand why something like:

y => {
    let yy = y * y
    return someFunction(yy) + someOtherFunction(yy)
}

wouldn't suffice (in the very minority of the cases)

Robert Mennell
@skatcat31
Mar 31 2017 15:37
I'd like to point out that let is block scoped and single pointed: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let
however each one is a different instance for the loop context
so where let is REALLY usefull is loops that need to snapshot that variable and NOT only get the last value
// from the MDN article
var list = document.getElementById('list');

for (let i = 1; i <= 5; i++) {
  let item = document.createElement('li');
  item.appendChild(document.createTextNode('Item ' + i));

  item.onclick = function(ev) {
    console.log('Item ' + i + ' is clicked.');
  };
  list.appendChild(item);
}

// to achieve the same effect with 'var'
// you've to create a different context
// using a closure to preserve the value
for (var i = 1; i <= 5; i++) {
  var item = document.createElement('li');
  item.appendChild(document.createTextNode('Item ' + i));

    (function(i){
        item.onclick = function(ev) {
            console.log('Item ' + i + ' is clicked.');
        };
    })(i);
  list.appendChild(item);
}
and in scoping private variables
Rick Medina
@rickmed
Mar 31 2017 15:44
functions like converge or usewith which break reading flow adds unnecessary cognitive load -it's just optimization of the wrong process (writing vs reading) imho
Matthew Willhite
@miwillhite
Mar 31 2017 15:54

@rickmed When I started with Ramda I would try to force myself into point free (unnecessarily). Often times now I find a piece of code where I did that and will try to acheive a balance…leaning toward the side of readability.

That being said converge and other "flow breaking” functions can be very useful, but maybe they can hide under the mask of a function that states its intention a little more clearly. I tend to use things like that in utility functions where I want precisely that combinator, but with a nicer API on top.

const friendlyFunc = function (x) { return converge(f, [g, identity])(x); }
Robert Mennell
@skatcat31
Mar 31 2017 15:55
@miwillhite :+1::+1::+1::+1::+1:
Robert Mennell
@skatcat31
Mar 31 2017 16:00

although if you're declaring it as a functional block instead of a lamda, then you should just

function friendlyFunc(x) { return converge(after, [left, right])(x); }

granted one of my co workers didn't like the converge writing in Ramda so he rewrote the api as

const Rconverge = ( after, ...before ) => R.converge(after, before)
much to our dismay when we had to debug his code... DOCUMENT YOUR APIS!
Jonah
@jonahx
Mar 31 2017 16:01
@rickmed I think your example is perfectly fine. I do slightly prefer the converge version though. I think we agree in principle, it’s just that I don’t feel converge breaks the flow. it’s perfeclty readable to me. the high-level pattern it represents is really common and it helps expressiveness to be able to capture it. converge isn’t the best name, and the js function syntax is less than ideal, but at least you’re still using the correct named concept. i’ve been learning J recently, and the converge concept is baked in at the syntax level — that’s how important it is seen to be. so in J (psuedocode) you can write square + double and it means converge(add, square, double)
Robert Mennell
@skatcat31
Mar 31 2017 16:07
@jonahx converge is great in mathematical use cases since it can set an order of precedence. I wouldn't be surprised if in a financial application if you have many nested converges and maps to set precidence of orders of opperations for calculating limits and derivitives in JS
Rick Medina
@rickmed
Mar 31 2017 16:25
Although, you personally may find it more/less readable, it does breaks reading flow and adds cognitive load . J's example is good/different -it reads straight left to right and/so argument order application is consistent with reading order (in english). With converge I need to read the docs how the args are applied (will this err? converge(div, x, y))
@jonahx
Jonah
@jonahx
Mar 31 2017 16:30
@rickmed yeah, like i said it’s not the ideal api. that said, isn’t what you’re calling flow just infix vs prefix application. your argument could be used against every lisp function. and while i do agree, i consider it a somewhat cosmetic point. ie, for me, having the converge concept named and at my disposal outweighs the inelegance of its api. at least in many cases.
Rick Medina
@rickmed
Mar 31 2017 16:39
@jonahx yeap. but in converge's specific case is that it combines prefix with implicit fn application with results. I'm curious what would you rename converge to?
Jonah
@jonahx
Mar 31 2017 16:40
@rickmed i’m fond of J’s visually suggestive term “fork"
although that has possibly confusing associations with unix processes
Rick Medina
@rickmed
Mar 31 2017 16:42
and tasks :)
Robert Mennell
@skatcat31
Mar 31 2017 16:42
and logic... really forking confusing
Rick Medina
@rickmed
Mar 31 2017 16:42
@jonahx but thank you. You made me realize that I would probably use converge with a different api (infix and different name?)
Jonah
@jonahx
Mar 31 2017 16:44
@skatcat31 :laughing: naming high-level concepts is hard. @rickmed :) or no name (like J).
Robert Mennell
@skatcat31
Mar 31 2017 16:45
@jonahx there are only two hard parts to programming: Cache invalidation adn naming things
Rick Medina
@rickmed
Mar 31 2017 16:45
@jonahx :) well add is an easy one since it has a symbol. How is it written for a custom function?
Jonah
@jonahx
Mar 31 2017 16:45
@skatcat31 i’m a huge believer in that. and i think naming things is #1
Robert Mennell
@skatcat31
Mar 31 2017 16:45
const converge = ( ...before, after ) =>R.converge(after, before)
Jonah
@jonahx
Mar 31 2017 16:46
@rickmed same way: fn1 customFn fn2 — that’s it. J is a work of art.
Robert Mennell
@skatcat31
Mar 31 2017 16:48
//assuming you only want to converge 2 functions... Converging is also useful with lenses and gets to extract a LOT of things out of an object in a specific manner
const converge = ( left, middle, right ) => R.converge(middle, [left, right]);
converge( add, subtract, multiply )( 4, 3 );
Jonah
@jonahx
Mar 31 2017 16:50
@skatcat31 good point. that solves @rickmed’s ordering issue.
Robert Mennell
@skatcat31
Mar 31 2017 16:51
@jonahx
converge( modPanel, [getUser, getPermissions, getMessages, getTickets] )(possibleMod)
Jonah
@jonahx
Mar 31 2017 16:54
@skatcat31 yes. i find it comes up more often in the binary case, though
Robert Mennell
@skatcat31
Mar 31 2017 16:56
the only thing I don't like about it is the array in it. After finally understanding my co workers code I ussually use his wrapper of ( after, ...before ) => R.converge( after, before )
Jonah
@jonahx
Mar 31 2017 16:56
@skatcat31 agreed. the array is unsightly.
Robert Mennell
@skatcat31
Mar 31 2017 16:56
it has it's purpose though
Jonah
@jonahx
Mar 31 2017 16:57
yes
i suppose you could parse a variable length arguments to jettison it, but then you’d give up currying
Rick Medina
@rickmed
Mar 31 2017 16:58
flipping it, better or worse?
converge( [getUser, getPermissions, getMessages, getTickets], modPanel )
yeah I don't like generally variadic fns bc of currying
Robert Mennell
@skatcat31
Mar 31 2017 16:59
just don't flip and remove:
converge( getUser, getPermissions, getMessages, getTickets, isMod);
pipe( getUser, getPermissions, getMessages, getTickets, isMod);
Jonah
@jonahx
Mar 31 2017 16:59
@rickmed i actually find that a bit more readable because left to right now matches the order of computation, but i assume the current order is because you’d more often curry the other way?
although honestly i can’t think of a good use case where i’d want to curry converge
eh, i guess i could think of one, i just don’t see myself using it in practice
Rick Medina
@rickmed
Mar 31 2017 17:02
@jonahx I tend to agree. I imagine trying to name that curried fn 0.o
Robert Mennell
@skatcat31
Mar 31 2017 17:02
@jonahx
const renderPanel = converge(userPanel);
Denis Stoyanov
@xgrommx
Mar 31 2017 17:02
@jonahx just use daggy or union-type (sum ADT or enum)
Robert Mennell
@skatcat31
Mar 31 2017 17:03
now jsut pass it your array of functions that fetch relevant things and BAM.
Jonah
@jonahx
Mar 31 2017 17:04
@xgrommx yeah, that would work well
Robert Mennell
@skatcat31
Mar 31 2017 17:05
basically converge with a curry is GREAT for renders that want to just concat a ton of output from other functions in an extensible manner
renderHTML( [ head, body, userInfo, sidebar, footer, scripts, endBody ], userData);
renderHTML( [head, body, userInfo, calander, sidebar, footer, scripts, partners, endBody], userData);
Jonah
@jonahx
Mar 31 2017 17:07
@skatcat31 thanks for the example, makes sense
Denis Stoyanov
@xgrommx
Mar 31 2017 17:07
compose(Wrapper, sequence(always, [Component1, Component2, Component3]))(data)
Rick Medina
@rickmed
Mar 31 2017 17:08
@skatcat31 good one :+1:
Jonah
@jonahx
Mar 31 2017 17:11
@xgrommx :thumbsup:
Robert Mennell
@skatcat31
Mar 31 2017 17:17
@xgrommx has a good point, there's more than one way to skin a cow
const render = ...args => ( sender, user ) =>  R.pipe( R.converge(String.concat, args), sender)(user);
const renderPanel = render( /*stuff*/);
// ... down the line
renderPanel( res.send, userModel ); //there's probably  way to clean this up with better currying
Jonah
@jonahx
Mar 31 2017 17:19
@rickmed apropos of our discussion about how point-free versions are occassionally worse than their pointy counterparts, I just ran into this dilemma, and opted for the pointy version:
  this.toString = () => map(invoker(0, 'toString'), playerActions).join(', ');
  this.toString = () => map(x => x.toString(), playerActions).join(', ')
Rick Medina
@rickmed
Mar 31 2017 17:21
@jonahx 100% regarding invoker. Plus, strings are buggy
obs, first class fn would be ideal, but js...
Jonah
@jonahx
Mar 31 2017 17:22
@rickmed and then there’s this example, which i posted on SO, where it’s not even a contest: http://stackoverflow.com/questions/36188328/writing-a-parameterless-function-in-ramda-in-a-point-free-style
the point-free version is a feat of contortion
Robert Mennell
@skatcat31
Mar 31 2017 17:23
@rickmed what do you mean first class function?
Rick Medina
@rickmed
Mar 31 2017 17:24
just if toString were a fn instead of a method
Robert Mennell
@skatcat31
Mar 31 2017 17:27
@rickmed Impliment it?
const toString = x => toString in x ? x.toString() : JSON.stringify(x) //or whatever...
Rick Medina
@rickmed
Mar 31 2017 17:27
@jonahx without lambdas it would be a different situation, so I can understand invoker's case in the past
Robert Mennell
@skatcat31
Mar 31 2017 17:28
crap what was that way to check if it was in the object and NOT the prototype???
Rick Medina
@rickmed
Mar 31 2017 17:28
@skatcat31 of course, but I wouldn't do it just to map(toString) vs map(x => x.toString()) one or couple of times
Robert Mennell
@skatcat31
Mar 31 2017 17:29
sure.. but now do it a couple of thousand times... leftPad is a very useful library
Rick Medina
@rickmed
Mar 31 2017 17:32
well, leftpad is like 10 lines vs a few characters lambda toString
Robert Mennell
@skatcat31
Mar 31 2017 17:34
const toString = x => Object.keys(x).indexOf('toString') > -1 ? x.toString() : JSON.stringify(x);
Jonah
@jonahx
Mar 31 2017 17:36
@skatcat31 def an improvement. i had to do this to make it work though:
const toString = x => x.toString ? x.toString() : JSON.stringify(x);
Robert Mennell
@skatcat31
Mar 31 2017 17:36
pretty sure that'll sitll hit the prototype
Rick Medina
@rickmed
Mar 31 2017 17:37
nah, "import toString from xxx" > "x => x.()" no matter what
Jonah
@jonahx
Mar 31 2017 17:38
@skatcat31 i don’t understand you last comment.
Robert Mennell
@skatcat31
Mar 31 2017 17:38
let me repl...
Rick Medina
@rickmed
Mar 31 2017 17:39
unless you put it on the global obj :smiling_imp:
or a babel plugin or something which injects a functional js prelude-ish
Jonah
@jonahx
Mar 31 2017 17:44
weird. i’m just running it in node and it works fine locally
@skatcat31 ^^
Rick Medina
@rickmed
Mar 31 2017 17:45
afaik, .keys() lists own enumerable, dot notation will look up the prototype
Jonah
@jonahx
Mar 31 2017 17:45
@skatcat31 oh i know why, bc the object i’m using it on was created with new, so its prototype is getting hit
glad i asked tho
Rick Medina
@rickmed
Mar 31 2017 17:46
in as well, as in for...in
Robert Mennell
@skatcat31
Mar 31 2017 17:48
@rickmed correct, but don't for get about accessors either x['prop'] which will hit the prototype as well.
Rick Medina
@rickmed
Mar 31 2017 17:48
yes
Robert Mennell
@skatcat31
Mar 31 2017 17:50
OMFG hasOwnProperty!
Robert Mennell
@skatcat31
Mar 31 2017 17:52
yes but I was lookign for a Ramda agnostic way of doing it...
The Ramda toString is much more capable(and VERY well done), but I don't always want Ramda.
Jonah
@jonahx
Mar 31 2017 18:04
when creating objects with new what do you all think about the practice of achieving a uniform interface (and also being more object-y) by not having any properties but only methods? so if you want to access obj.x you would need to do obj.x() which would dispatch to always(x) internally.
Robert Mennell
@skatcat31
Mar 31 2017 18:04
const toString = x => x.hasOwnProperty( 'toString' ) ? x.toString() : JSON.stringify(x);
@jonahx x.x().x().x().x().x().x().x().....
Jonah
@jonahx
Mar 31 2017 18:07
@skatcat31 not sure i follow. to be clear, i’m not talking about a fluent interface but a uniform one. ie, not having some things which are properties and some which are methods. “everything is a message"
Robert Mennell
@skatcat31
Mar 31 2017 18:09
@jonahx so if x = {y} && y = 2 then x.y() == 2 && x.y == x.y()?
Jonah
@jonahx
Mar 31 2017 18:09
@skatcat31 yes
Robert Mennell
@skatcat31
Mar 31 2017 18:10
because primitives are VASTLY different than their object representations
@jonahx '' !== new String() and that matters in a few very important cases
Jonah
@jonahx
Mar 31 2017 18:12
@skatcat31 i think that’s orthagonal to my question. the basic idea is that if you’re working with an object (at least the kind that is more than just a data container) you never have to remember if something is a property access or a method. because everything is a method, as in ruby.
Gabe Johnson
@gabejohnson
Mar 31 2017 18:19
@jonahx you could do that manually, or use a Proxy to do it
Jonah
@jonahx
Mar 31 2017 18:20
@gabejohnson i’ve been doing it manually. i was curious what people’s thoughts were on its value. i thought proxies hooked into the process of getting / setting, but don’t actually change the way you call it. that is, you’re still doing property access syntactically.
Gabe Johnson
@gabejohnson
Mar 31 2017 18:21
but you could intercept all calls and if there's no method by that name, return the value of the property
so would you do x.y() for access and x.y(z) for mutation?
Jonah
@jonahx
Mar 31 2017 18:22
@gabejohnson ah, i wasn’t aware you could do an intercept all. is the performance bad?
Gabe Johnson
@gabejohnson
Mar 31 2017 18:23
no idea
Jonah
@jonahx
Mar 31 2017 18:23
thx for the idea
Gabe Johnson
@gabejohnson
Mar 31 2017 18:23
:thumbsup:
It could be interesting to implement a jQuery like getter/setter interface and have the setter return a new instance
then it's immutable
Jonah
@jonahx
Mar 31 2017 18:24
@gabejohnson yeah that’s what i always do with setters
Gabe Johnson
@gabejohnson
Mar 31 2017 18:24
a lot of people don't like that sort of interface though
@jonahx cool
Robert Mennell
@skatcat31
Mar 31 2017 18:24
This feels like the context approach of 'Context EVERYTHING'
Jonah
@jonahx
Mar 31 2017 18:25
@gabejohnson imo it’s the only way to do OO properly
Gabe Johnson
@gabejohnson
Mar 31 2017 18:26
@jonahx like y.x = z returns a new y?
or did you mean setter method?
Robert Mennell
@skatcat31
Mar 31 2017 18:29
@jonahx there is one issue with contexting all the things... are they functions, or are they objects or are they primitives? and how do we know when to x.y().map() or x.y.map() and so forth.
Jonah
@jonahx
Mar 31 2017 18:31
@gabejohnson since it’s a method the syntax would be y.x(new val) which return a new copy of y
Robert Mennell
@skatcat31
Mar 31 2017 18:31
@jonahx so why not just do y.map?
Jonah
@jonahx
Mar 31 2017 18:32
@skatcat31 i don’t follow. you could have many properties...
Robert Mennell
@skatcat31
Mar 31 2017 18:33
@jonahx y.x.map()
Jonah
@jonahx
Mar 31 2017 18:33
think person.firstName(‘new name’) and person.lastName(‘new last name’), each of which returns a new Person
Robert Mennell
@skatcat31
Mar 31 2017 18:33
does that return a new version of y, or x?
Gabe Johnson
@gabejohnson
Mar 31 2017 18:33
@jonahx sorry. What I said didn't make sense. Time to eat lunch
Robert Mennell
@skatcat31
Mar 31 2017 18:34
where else are you going to get values for the other properties? copy them from the object? Or just leave them undefined? Is it a new instance, or a factory? Can it be a new instance?
... continue list of questions and implications
Gabe Johnson
@gabejohnson
Mar 31 2017 18:34
@skatcat31 you copy them from this and it's a new instance
Jonah
@jonahx
Mar 31 2017 18:34
@skatcat31 well you’d never have y.x only y.x() but i still feel like i’m perhaps not following. i don’t see any of those questions as posing a difficulty.
you would use the objects ctor to make the new copy
Robert Mennell
@skatcat31
Mar 31 2017 18:37
person.firstName.x == person.firstName().x != person.firstName('new Name').x != new person('new name').x != person.firstName('new name').firstName('newer name').firstName('newestName').x
Jonah
@jonahx
Mar 31 2017 18:37
@skatcat31 there is no x there
just person.firstName()
Robert Mennell
@skatcat31
Mar 31 2017 18:38
@jonahx except I put one there: person.firstName.x = VALUE
Jonah
@jonahx
Mar 31 2017 18:38
@skatcat31 that’s invalid under my proposal
as is firstName without the parens
Robert Mennell
@skatcat31
Mar 31 2017 18:38
then how do I nest something?
Jonah
@jonahx
Mar 31 2017 18:40
person.firstName().length works, eg (with length grandfathered in bc it’s a native string)
i still believe we’re misunderstanding one another tho
Robert Mennell
@skatcat31
Mar 31 2017 18:42
It sounds like you want to move back to OOP and try to have OOP with first order functions?
It sounds like to me your model actually break OOP by not allowing mutation?
Jonah
@jonahx
Mar 31 2017 18:44
@skatcat31 no, i don’t think the first of what you said is true. and in the 2nd i guess we get into the discussion of what’s “true OOP” which isn’t something i care about. but for me objects without mutations are the way to go.
if you want to call that “Jonah’s crazy OOP” i’m okay with that :)
Robert Mennell
@skatcat31
Mar 31 2017 18:45
@jonahx actually it sounds more like Haskell
Jonah
@jonahx
Mar 31 2017 18:46
@skatcat31 i would say that’s fair :)
Robert Mennell
@skatcat31
Mar 31 2017 18:47
@jonahx x.function.notFunction.function.function is doable in javacsript.
I don't know why, but it is, and I think that's pretty novel... for some reason?
Jonah
@jonahx
Mar 31 2017 18:52
@skatcat31 yeah i can’t think of another language that does that. basically a result of defineProperty allowing you to invoke whatever you want, leaving the choice of dot notation or functoin invocation syntax to the user. It’s the kind of flexibility I’m inclined to limit in my own code for the sake uniform interfaces and the principle of least surprise
Robert Mennell
@skatcat31
Mar 31 2017 18:53
@jonahx It allso allows you to(in non strict) change this context
x.y.function() //thix == x vs z = x.y; z.function() // this != x unless bound to x vs z = x.y.function; z() // this is either undefined or the global(strict v non)
Gabe Johnson
@gabejohnson
Mar 31 2017 18:56
x.y.function() //this == x.y
Robert Mennell
@skatcat31
Mar 31 2017 18:56
@gabejohnson possibly... this is still a confusing concept :smile:
Gabe Johnson
@gabejohnson
Mar 31 2017 18:57
yes it is
I still reread this constantly
Gabe Johnson
@gabejohnson
Mar 31 2017 18:57
I sometimes think of it as the reified dynamic context of a function
like dynamic scope
Robert Mennell
@skatcat31
Mar 31 2017 18:58
which is good/bad in quantum state...
Gabe Johnson
@gabejohnson
Mar 31 2017 18:58
instead of "this is the object I'm a member of"
Rick Medina
@rickmed
Mar 31 2017 18:58
"I think I get the idea!", "what should we call it?", "this"...what could possibly go wrong....
Gabe Johnson
@gabejohnson
Mar 31 2017 18:59
From an OO perspective it makes sense. When I'm thinking functionally I think of it as env
Rick Medina
@rickmed
Mar 31 2017 19:01
jk...but it's still supremely confusing: this, x.y.function() //this = ?, this inside a function, bind...
lunchtime... bbl
Rick Medina
@rickmed
Mar 31 2017 19:02
context/object is a very hard thing to delimit when everything is one
Rick Medina
@rickmed
Mar 31 2017 19:08
(I'm a bit ranty today :) )
Gabe Johnson
@gabejohnson
Mar 31 2017 19:09
@rickmed that was me yesterday
Jonah
@jonahx
Mar 31 2017 20:20
is it possible to avoid all the boilerplate inherent in creating properties for the parameters passed into a ctor? I want to just say, “do this for all the parameters”:
function MyClass(arg1, arg2) {
  this.arg1 = arg1;
  this.arg2 = arg2;
}
Rick Medina
@rickmed
Mar 31 2017 20:22
daggy?
Jonah
@jonahx
Mar 31 2017 20:23
@rickmed yeah, that’s what i want. i was curious if there was a native way to do it
Robert Mennell
@skatcat31
Mar 31 2017 20:24
@gabejohnson I htink for you and me ranty just suddenly flips and off we go...
Rick Medina
@rickmed
Mar 31 2017 20:27
@jonahx that is the less boilerplate way I know
native
Jonah
@jonahx
Mar 31 2017 20:27
thx
Gabe Johnson
@gabejohnson
Mar 31 2017 20:27
@skatcat31 I think you're right
Robert Mennell
@skatcat31
Mar 31 2017 20:41
@jonahx Not if you need names... Best you could do is offload it but I'm pretty sure it's just as much work... just easier to change down the line
const MyProps = ['p1','p2'...]
function MyClass(...args){
  return R.zipObj(MyProps, args);
}
// cow skin
const MyProps = R.zipObj( ['a','b',...]);
const MyClass = ...a => MyProps(a)
Of course... the problem then becomes with the second example how the heck do you add functions...
Robert Mennell
@skatcat31
Mar 31 2017 20:46
You could probably do some trickery with Object.create and some sort of this referencing method collection...
// cow skin assuming I remember Object.call correctly
const MyMethods = {
  methodWithThisReferences
}
const MyProps = R.zipObj( ['a','b',...]);
const MyClass = ...a => Pipe( MyProps, MyMethods.call )(a)
Robert Mennell
@skatcat31
Mar 31 2017 20:51
No wait... I screwed something up...
Eitehr way there is a functional way to generate a class factory that will be easier to maintain in the long run since modification of boilerplate means immeadiate change to entire class
I'm certain I did something wrong... but reference this for what I did wrong: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create
Robert Mennell
@skatcat31
Mar 31 2017 21:25
// cow skin version2
const MyMethods = () => {
  this.method = function
}
const MyProps = R.zipObj( ['a','b',...]);
const MyClass = ...a => Pipe( MyProps, MyMethods.call )(a)
Stefano Vozza
@svozza
Mar 31 2017 21:42
There are only two hard problems in computer science : cache invalidation, naming things and off by one errors.
Johnny Hauser
@m59peacemaker
Mar 31 2017 22:17
how would you transduce the values of an object?
This sucks t.into([], t.map(over(lensIndex(1), inc)), {foo: 1, bar: 2})
agstrauss
@agstrauss
Mar 31 2017 22:28
Hi everyone! I'm new to ramda and I was wondering if there is a function to map objects with a mapper object. It would be something like this:
const obj = {
  a: 1,
  b: 2
};

const map = {
  x: {
    y: R.prop('a')
  },
  z: R.compose(R.inc, R.prop('b'))
};

mapperImLookingFor(map, obj);
// returns:
//
// {
//   x: {
//     y: 1
//   },
//   z: 3
// }
or at least a shallow version... thanks!
Rick Medina
@rickmed
Mar 31 2017 22:30
@agstrauss evolve?