These are chat archives for ramda/ramda

20th
Apr 2017
Denis Stoyanov
@xgrommx
Apr 20 2017 03:09
@ram-bot const applyN = curry((n, f) => reduceRight(compose, identity, repeat(f, n))); applyN(2, add(10))(10)
ram-bot
@ram-bot
Apr 20 2017 03:09
30
Stephan Meijer
@smeijer
Apr 20 2017 11:08
Any advice on how to make this point free? I guess with useWith, but I cannot make it work:
R.curry((rules, query) => L.set(
  ['tasks', '$elemMatch', '$or'],
  filter(rules),
  query,
));
Kurt Milam
@kurtmilam
Apr 20 2017 11:16
@smeijer There's a gitter room for calmm (the toolset of which partial.lenses is a component), in case you weren't aware.
If you ask over there, however, you'll probably be told that it's not worth the hassle to make that point free :)
Stephan Meijer
@smeijer
Apr 20 2017 11:20
Yes, I found the room for calmm, but I thought making it point free is more a ramda thing than the lens thing :)
Kurt Milam
@kurtmilam
Apr 20 2017 11:20
L.set is already curried, I believe. This should work (although not yet completely point-free):
(rules) => L.set(
  ['tasks', '$elemMatch', '$or'],
  filter(rules),
);
Stephan Meijer
@smeijer
Apr 20 2017 11:21
True, I was trying to also remove the rules part. Yet, i believe that i might be leaving the lamba parts. It does add more clearity to code
I try to get used to point free style. But I'm unsure which one I like more. Point free; or the lambda functions.
Kurt Milam
@kurtmilam
Apr 20 2017 11:23
Yeah, point-free is fun as code golf, but I don't think it makes a sense to expend a lot of effort to get there.
This might work:
const fn = R.compose( L.set(['tasks', '$elemMatch', '$or']), filter )
//might need to call it like this:
fn( rules )( query )
Kurt Milam
@kurtmilam
Apr 20 2017 11:30
I spent a lot of time converting some existing code to point-free style and will probably convert it back. I think point-free is often harder to read and reason about. I think it also often requires a lot of extra code and cruft to get there ( things like R.converge ). Although if the second example I gave works, that function is probably a reasonable candidate for doing in a point-free manner.
Stephan Meijer
@smeijer
Apr 20 2017 11:31
Thanks, it works :) But I like the curry style. Either call with (x, y, z), or (x)(y)(z). So came up with:
R.useWith(
  L.set(['tasks', '$elemMatch', '$or']),
  [filter, R.identity],
);
For the rest, exactly what you write. Point-free is often harder to read. I just want to get used to it, so I can decide what direction to go, based on correct knowledge instead of the lack of knowledge.
Kurt Milam
@kurtmilam
Apr 20 2017 11:35
:thumbsup: I like having the option of (x, y) or (x)(y), but I've recently started writing more fns that are manually curried (must be called like (x)(y)). Functions curried with Ramda's curry are significantly slower than functions curried manually.
James Forbes
@JAForbes
Apr 20 2017 12:38
@kurtmilam yeah I agree, I often write it both ways and pick whichever is more obvious, though I disagree converge is cruft, it can be pretty handy
Stefano Vozza
@svozza
Apr 20 2017 12:41
@kurtmilam that benchmark looks a bit suspicious
Kurt Milam
@kurtmilam
Apr 20 2017 12:41
@JAForbes I certainly use converge, so I wouldn't say it's necessarily cruft in all cases. Rather, I mean there are plenty of cases where I can either write a function in a pointful manner with no converge, or I have to add converge in order to make it point-free. In those cases, I'd generally tend toward the pointful variant.
@svozza What seems wrong with it? It's based on one I found that I believe was created by CrossEye.
If you have suggestions for improvement, please let me know. I basically just took the one I found and made some minor modifications to it (bringing in a newer version of ramda, mostly).
Stefano Vozza
@svozza
Apr 20 2017 12:49
what i mean is that when you see massive differences like that there's always a chance there's been some compiler trickery
i'm always suspicious of microbenchmarks tbh
Kurt Milam
@kurtmilam
Apr 20 2017 12:50
@svozza Interesting. I was under the impression that Ramda's auto-currying was expensive, so I wasn't surprised by the results.
Stefano Vozza
@svozza
Apr 20 2017 13:05
Vyacheslav Egorov has a good talk on this stuff
Kurt Milam
@kurtmilam
Apr 20 2017 13:07
I'll take a look. I wonder whether there's any way to actually test the performance of Ramda's auto-curry to other methods of currying.
sorry, was hard to find
Kurt Milam
@kurtmilam
Apr 20 2017 13:09
already watching in another tab. thanks!
James Forbes
@JAForbes
Apr 20 2017 13:09
@kurtmilam I think if you create a benchmark then print deopts and see what the compilers actually doing, that would do it
Stefano Vozza
@svozza
Apr 20 2017 13:09
haha
@kurtmilam you're quicker than me! there's a benchmark we can agree on
Kurt Milam
@kurtmilam
Apr 20 2017 13:11
So I guess one question would be whether functions auto-curried by Ramda are more difficult for the compiler to optimize, and whether the difficulty is one that's likely to be overcome in the future.
I mean, if manually curried functions are easier for compilers to optimize, wouldn't that mean that, de facto, manually curried functions would be faster than ramda curried variants?
Stefano Vozza
@svozza
Apr 20 2017 13:12
i'm pretty sure ramda's curry is slower than normal ones, mainly because of the placeholder
but i just don't think it's 97% slower
Kurt Milam
@kurtmilam
Apr 20 2017 13:13
I'll hold my questions until after I finish watching the talk.
James Forbes
@JAForbes
Apr 20 2017 13:25

@kurtmilam yeah not necessarily, the fact benchmarks are so simple and isolated makes them poor examples of compiler behaviour in an application.

Its kind of reminds me of our only recent understanding of the importance of various bacteria in our gut. Science tends to isolate to serve the scientific method, but as soon as you do that, you lose context, and that can significantly change your results. So maybe bacteria x seems useless, or even harmful in isolation, but in context with millions of other bacterium, they are necessary for our health. Which is a challenge for experiments.

Kurt Milam
@kurtmilam
Apr 20 2017 13:28
Right, I see what you're saying (he's covering that in the talk, as well). If you're measuring assigning the result of some function to a variable that is never used, the compiler may just eliminate the function call, altogether, which it wouldn't do if you were actually using the result of the function call in real-world code.
James Forbes
@JAForbes
Apr 20 2017 13:30
and I think even worse, at the time of his talk, v8 was less advanced than it is now
so at this point v8 may just delete a loop, or a function entirely
I think at the time It may have only deleted the loop body, which is still super fast
Rick Medina
@rickmed
Apr 20 2017 13:33
I've seen that talk and made other related benchmarks previously and I can believe ramda's being 20x slower, bc of placeholder support and nested currying, also engines are not optimized at all for fp (creating functions), so even one additional operation like that is significant overhead
that said, as "premature optimization", it may be insignificant in your code base
James Forbes
@JAForbes
Apr 20 2017 13:37

I don't have ramda's curry committed to memory, but technically it could be faster in certain situations because it doesn't necessarily need to create each intermediate function.

e.g.

var f1 = curry( (a,b,c,d,e,f,g) => ... )
var f2 = a => b => c => d => e => f => g =>

f1(1,2,3,4,5,6) // no intermediate function creations per arg
f2(1)(2)(3)(4)(5)(6)

But again, not saying ramda would be faster, just saying its all meaningless without a good benchmark.

and then what are we measuring, invocation, creation?
and things change all the time, bind used to be really slow, and now its not
so intuition is kind of useless
and then that's ignoring different engines...
Rick Medina
@rickmed
Apr 20 2017 13:41
sure! but iirc that benchmark is not testing f()() but f(). I never use ()() bc of my comment above, I only do manual currying when I know it will be partially applied and executed with last arg
eg: partial application for testing and for runtime
James Forbes
@JAForbes
Apr 20 2017 13:43

I had to write some data intensive code in node a few years back that had to be fast, and I dove into printing --trace-deopt --trace-opt, I was constantly surprised by the behaviour of the compiler, often things I was positive would be perf boosts weren't and vice versa.

I ended up giving up on almost everything other than indexing and monomorphic hidden classes and that alone was a huge win. But I used ramda, and took it out, and put it back in and it was in the noise.

I was just prototyping stuff in ramda, and then I'd rewrite it with imperative code. Of course this was a specific context, so ymmv, but I guess my point is, its all kind of unpredictable.
Weird things like keeping ram under 1 gig would make a huge difference, even if the pc had tons of ram
v8 would completely change strategy the moment memory usage passed 1 gig
so there's just some if statement somewhere that radically changes behaviour, you can't reason about that stuff
Rick Medina
@rickmed
Apr 20 2017 13:46
I get it and agree :). Mine is just about that most of the times there is no free lunch (more code, slower parsing and execution, especially since you can't predict engine's optimizations) and R.curry is significant more code (in the context of those benchmarks)
Kurt Milam
@kurtmilam
Apr 20 2017 13:47
I try to avoid premature optimization, but I have run into the need to optimize, so I generally at least keep it in the back of my mind.
James Forbes
@JAForbes
Apr 20 2017 13:47
I think the "premature optimization" thing is several conflated ideas
I think we should always care about performance, always. But we shouldn't prematurely make "performance optimizations" without verifying they do anything, often it will end up in spaghetti code and make zero difference, if not make it worse.
Kurt Milam
@kurtmilam
Apr 20 2017 13:49
SVG drag and drop is something that, at least 5 or 6 years ago, I was not able to make happen with sufficient fluidity using any of the libraries I tried at the time, so I ended up writing my own.
(didn't write my own SVG library - I just worked up my own, optimized drag and drop functions).
It's certainly possible that modern engines + modern libraries have obviated those performance issues in the meantime.
James Forbes
@JAForbes
Apr 20 2017 13:51
drag and drop is a great example, we could optimize the js all we want, but if you aren't using css transform, its all for naught
Kurt Milam
@kurtmilam
Apr 20 2017 13:52
I wasn't/amn't using CSS transform.
James Forbes
@JAForbes
Apr 20 2017 13:52
@kurtmilam what do you do?
Kurt Milam
@kurtmilam
Apr 20 2017 13:52
I was updating the x and y coordinates on the element being dragged.
James Forbes
@JAForbes
Apr 20 2017 13:54
oh is this like vector drawing, or are these solid shapes that are simply translating x/y?
Kurt Milam
@kurtmilam
Apr 20 2017 13:55
these are solid shapes with snap-to lines.
So, a draggable shape ends up centered on one of the lines in another shape. When dragging the shape, there's a snap-to line connecting the two shapes, showing where the draggable shape will slide into place if you stop dragging.
James Forbes
@JAForbes
Apr 20 2017 13:57

I'd put the svg in a div, and translate that via css transform, then when you stop moving, you can render that svg again in the layer with the other svg, if the layer is moving via css tranform, its all on the gpu, and there's no reflow.

Whenever something moves, promote it to a layer.

Kurt Milam
@kurtmilam
Apr 20 2017 13:59
I'll give that a look. Fortunately, the solution I came up with ended up being fast enough, but I'm re-working that application, so I'll take your advice into consideration when I get around to that part of the application.
James Forbes
@JAForbes
Apr 20 2017 14:00
yeah I don't know the context, your solution is probably fine
I guess I'm saying, the bottleneck there isn't js, its interaction with the dom, reflow. And if you can move translations onto the gpu, that has just moved the vast majority of work off the thread, and now currying or not currying etc is kind of unimportant (not to say currying was relevant in your context, but just using it as an example)
Kurt Milam
@kurtmilam
Apr 20 2017 14:02
I'm sure a lot has changed since I wrote it 6 or 7 years ago. I get what you're saying about js not being the bottleneck there, but at the time, inefficient js was at least one source of bottleneck that I was able to address in a way that made a palpable improvement to the performance.
James Forbes
@JAForbes
Apr 20 2017 14:02
its like, react/mithril/etc is technically extremely wasteful, we're running all this code all the time that probably doesn't need to run. But its ok, because that isn't the bottleneck, and if we realise that we get this great abstraction/interface, that on its own seems expensive, but in context its fast.
yeah 7 years ago!
Kurt Milam
@kurtmilam
Apr 20 2017 14:03
:D
James Forbes
@JAForbes
Apr 20 2017 14:03
:D
Kurt Milam
@kurtmilam
Apr 20 2017 14:03
Had I started writing it this year, I probably wouldn't have ever noticed a js-related bottleneck :)
Rick Medina
@rickmed
Apr 20 2017 14:04
:smile:
James Forbes
@JAForbes
Apr 20 2017 14:04
The only perf bottleneck I seem to run into anymore, is sanctuary. But I kind of see it as a blessing, like cpu throttling, if it feels fast with runtime typechecking on, then it will fly in prod
cpu throttling is there, but I never turn it on, but sanctuary is useful, so its kind of keeping me honest
Rick Medina
@rickmed
Apr 20 2017 14:05
on the back end?
James Forbes
@JAForbes
Apr 20 2017 14:05
front end
I use it on the backend but I don't notice as much
Kurt Milam
@kurtmilam
Apr 20 2017 14:05
Further back than that, say 8 or 9 years ago, I came up with my own vdom solution for a pair of form elements that everyone thought couldn't be done with acceptable performance.
The client wanted a 'pick list' control that consisted of two multi select boxes where you could move items back and forth between the lists (items on the left were available but unassigned, items on the right were assigned).
The problem was that there were 11K items, total.
James Forbes
@JAForbes
Apr 20 2017 14:08
wow that's pretty incredible @kurtmilam, react only came out 4 years ago, you were ahead of the curve!
Kurt Milam
@kurtmilam
Apr 20 2017 14:08
Most of the bottleneck on that was DOM-related. The client HAD to have it. I was a PM / analyst / consultant on that project. The customer's devs couldn't figure it out, and my devs also told me it was impossible :D
Target browser: IE 6+
James Forbes
@JAForbes
Apr 20 2017 14:09
oh no! ie6!
Kurt Milam
@kurtmilam
Apr 20 2017 14:10
The naive solution was to put the two lists on the page via HTML, populate each from an ajax call and when 'moving' an item from one list to another, actually removing it from one list and adding it to the other (in its proper alphabetical position).
My solution was to eschew the selects, mock them with divs and create and populate the divs in js before adding them to the screen.
And rather than adding and removing items from the lists, I simply hid or showed them.
I also found that creating one div in js, then cloning it was faster than creating them separately. I spent a while testing various optimizations, and the end result actually worked pretty smoothly, much to everyone's surprise.
Next thing I know, that custom control is showing up all over the place in their app, a web-based ERM for hospitals.
James Forbes
@JAForbes
Apr 20 2017 14:14
that's great!
Kurt Milam
@kurtmilam
Apr 20 2017 14:14
Fun times :D
James Forbes
@JAForbes
Apr 20 2017 14:15
One trick I do with big lists/tables is to not bother with adding/removing the li or td, but just their content. Its kind of like level of detail in game dev. So much less effort, I do that first before worrying about occlusion culling or anything more serious. Nearly always works. Even on mobile.
and its great too even if you do have to remove stuff that is offscreen, you can give yourself a bit more of a buffer of offscreen items for safety for fast scrolls, but just clear their content
but yeah lots of failed perf experiments
I worked at a photo sharing site, and we built this memory pooling thing for images
recycling objects/images manually
total waste of time
we even reused backbone view instances!
pointless
we had some method, I forget what it was called, but it basically cleared manually all the properties and state of an instance
but just re-instantiating a fresh one turned out to be exactly the same speed, if not faster, so it added all this complexity
James Forbes
@JAForbes
Apr 20 2017 14:20
I mean the gc was probably happy, but it made no difference to frame rate from what I could measure
that's the sort of thing where it looks good on paper "stop creating new objects, just reuse old ones"
but v8 says no
Kurt Milam
@kurtmilam
Apr 20 2017 14:26
sorry, stepped away to get a drink - catching up.
Bohdan Ganicky
@bganicky
Apr 20 2017 14:26

Hi there, I have a Ramda noob question. I have this data transformation:

const testCSA = (flightNumber: string): boolean => {
  return /^8[\d]{3}$/.test(flightNumber)
}
const destsCSA = R.compose(
  R.uniq,
  R.map(R.prop('arrIATA')),
  R.filter(f => testCSA(f.flightNumber))
)(flights) // flights: Array<FlightObject>

Is there a way to clean up the filter line to avoid using f two times? Thanks!

Kurt Milam
@kurtmilam
Apr 20 2017 14:27
@JAForbes yeah, it's certainly possible to engage in pointless early 'optimization'. It's a real drag when you add tons of complexity to the system and don't even end up with noticeable performance gains.
It's interesting that they invested so much effort into that complex system without asking whether they were getting anything of value in return.
R.filter({ flightNumber } => testCSA(flightNumber))?
I think that's right @bganicky
James Forbes
@JAForbes
Apr 20 2017 14:29
@kurtmilam I like it
Kurt Milam
@kurtmilam
Apr 20 2017 14:31
:thumbsup: I've been dabbling in calmm lately (the toolset of which partial.lenses is a part). The developer uses lots of destructuring in his examples, so I've been getting a little more comfortable with it.
James Forbes
@JAForbes
Apr 20 2017 14:31
@kurtmilam yeah we just fell into the intuition optimization trap, and with small repros it was faster
Yeah destructuring is so good
Kurt Milam
@kurtmilam
Apr 20 2017 14:32
Agreed!
James Forbes
@JAForbes
Apr 20 2017 14:32
I had to log a lot of stuff today in the repl and it was invaluable
var { schedule_id, schedule_name, schedule_versions: [ {schedule_version_id} ] } = schedule
;({ schedule_id, schedule_name, schedule_version_id })
instead of going schedule.schedule_versions[0].schedule_version_id, and then checking each other property
Kurt Milam
@kurtmilam
Apr 20 2017 14:33
Awesome!
James Forbes
@JAForbes
Apr 20 2017 14:33
and then throw it in console.table
heaven
pretty cool it works on any iterator too
its really cool for pulling values out
Kurt Milam
@kurtmilam
Apr 20 2017 14:34
huh. I've never used console.table. Thanks for the tip.
James Forbes
@JAForbes
Apr 20 2017 14:34
:thumbsup:
paldepinds union-type works with destructuring via iterators ( so does my sanctuary port ), its super cool
though I'm thinking of removing it :D
Kurt Milam
@kurtmilam
Apr 20 2017 14:35
I've been meaning to look into paldepind's union-type.
James Forbes
@JAForbes
Apr 20 2017 14:36
yeah its a great library
Kurt Milam
@kurtmilam
Apr 20 2017 14:36
thinking of removing Sanctuary or union-type?
James Forbes
@JAForbes
Apr 20 2017 14:36
removing the iterator trick
from my port
I'm planning to remove a lot of stuff
no methods, no values spread, no instance casing
not because it isn't cool, but just because I find myself not using it, and question the complexity it adds
right now its a fairly faithful port but it just uses sanctuary behind the scenes for better error messages
Kurt Milam
@kurtmilam
Apr 20 2017 14:38
Gotcha. I'm trying to figure out how something like that would work into an application based on calmm.
Bohdan Ganicky
@bganicky
Apr 20 2017 14:38
@kurtmilam Thanks! I always forget all the clever uses of destructuring. :)
James Forbes
@JAForbes
Apr 20 2017 14:38
it works well with lenses, particularly for making null states unrepresentable
Kurt Milam
@kurtmilam
Apr 20 2017 14:39
After working on my mithril steam/atom state solution and talking with polytypic, the main calmm developer, I decided it didn't make sense to reinvent the wheel, and he already had so much more built into his system than I'd come close to approaching.
James Forbes
@JAForbes
Apr 20 2017 14:39
e.g. In my app we've got schedules, and you can load the app to a particular context via the url, but we may not have all the other fields of a schedule yet. So in the state object you'll have a lot of undefined values
But you can solve that by just explicitly stating the different states it can be in:
const $Schedule = Sum.Named('Schedule', {
    Empty: {}
    ,Id: { schedule_id: $UUID }
    ,Name: { schedule_name: $.String }
    ,Loaded: {
        schedule_id: $UUID
        ,schedule_name: $.String
        ,schedule_versions: $SortedScheduleVersionList
    }
})
Kurt Milam
@kurtmilam
Apr 20 2017 14:40
@bganicky :thumbsup:
Interesting. I'm trying to work out what's going on there.
James Forbes
@JAForbes
Apr 20 2017 14:41
now lets say the schedule is just an Id state, well that's ok, a lens could write more data to it, and we can detect that (in a stream, or a reducer or whatever) and change it state. But the rest of the app basically won't use it until the $Schedule state says it can be used. And you can enforce that by always using case instead of grabbing properties that may be undefined
Kurt Milam
@kurtmilam
Apr 20 2017 14:41
Ah you're going to explain it :D
James Forbes
@JAForbes
Apr 20 2017 14:42
Ah sorry I'll unpack it a bit
Kurt Milam
@kurtmilam
Apr 20 2017 14:42
no worries, your explanation already makes it clearer.
James Forbes
@JAForbes
Apr 20 2017 14:42
That $Schedule is an object with some constructors on it
So you can create a $Schedule.Id( someId )
that returns an object that is of that type ( so to speak )
We can then safely interact with it via case
const s =  $Schedule.Id( someId )

const name = 
  $Schedule.case({
    Id: () => Nothing
    _: () => Just( s.schedule_name )
  })
The _ just means, any other state
Kurt Milam
@kurtmilam
Apr 20 2017 14:44
Gotcha.
James Forbes
@JAForbes
Apr 20 2017 14:44
The other 2 states will have a schedule_name
If you leave the _ off, and you miss a state, sanctuary will throw an error, because we haven't handled all the cases
The case also currently will pass a spread of values to each case function
Kurt Milam
@kurtmilam
Apr 20 2017 14:45
I like that convention. Usually write _ => 123 rather than () => 123 these days.
James Forbes
@JAForbes
Apr 20 2017 14:45
but I've found that's kind of annoying, it'd be better for it to just pass the entire object
so that will change in the future
so in that example, Id actually receives the id value as the first arg
Kurt Milam
@kurtmilam
Apr 20 2017 14:45
Yeah, I've run into that before. Passing a spread at first, then realizing later that you'll need more than what you passed, and eventually ending up passing the whole object.
James Forbes
@JAForbes
Apr 20 2017 14:46
What's cool is, $Schedule is a valid sanctuary type, so you can use it anywhere sanctuary works
And you can also use sanctuary-def types in your definition
you'll notice that $UUID thing
I have a type module for that, that I use app wide (client and server)
const $ = require('sanctuary-def')

const UUID_PATTERN =
    /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i

const $UUID = $.NullaryType(
    'defunctzombie/node-uuid'
    , 'https://github.com/defunctzombie/node-uuid'
    , s => UUID_PATTERN.test(s)
)

export default $UUID
Kurt Milam
@kurtmilam
Apr 20 2017 14:47
That is cool. I've been meaning to take a closer look at Sanctuary, as well, but it seems like I always have something else to learn, first.
James Forbes
@JAForbes
Apr 20 2017 14:47
That $UUID is a sanctuary-def type, I can put in a function signature, or a sum-type definition, and get meaningful type errors with links to docs etc if some invalid value flows through the system
Kurt Milam
@kurtmilam
Apr 20 2017 14:47
That's awesome.
James Forbes
@JAForbes
Apr 20 2017 14:47
Yeah its really awesome!
and you can turn type checking off in prod
ScottFreeCode @ScottFreeCode unlurks
James Forbes
@JAForbes
Apr 20 2017 14:48
so I have a browserify thing that just injects process.env.CHECK_TYPES=true to the development bundle
in prod, no type checking, no performance issues
Kurt Milam
@kurtmilam
Apr 20 2017 14:48
Cool. On during development when it helps, off during production when it could hinder.
James Forbes
@JAForbes
Apr 20 2017 14:49
yep
and you can create separate "environments" in different areas of the codebase
so technically you could keep it on in some areas of your prod code
if it wasn't a hot path
sanctuary isn't really slow, its just noticeable in certain instances (big data sets I've found)
Kurt Milam
@kurtmilam
Apr 20 2017 14:49
That's nice (granular control of typedef checking)
James Forbes
@JAForbes
Apr 20 2017 14:50
it catches lots of silly errors though, I've found it more useful than typescript which surprised me
I think the type system is just better
Scott Santucci
@ScottFreeCode
Apr 20 2017 14:50
Is there a good functional way to handle parallelization, where a main process needs results in order but you want them to be processed in whatever order in some message-passing worker processes, and still guarantee that each input is only handled once resulting in resolution of the output once? (Basically, I'd like an input -> output flow without risky state, but... where the action gets farmed out elsewhere. I have this vague feeling I need to learn the IO monad or something like that...)
James Forbes
@JAForbes
Apr 20 2017 14:51
@ScottFreeCode does each item depend on the previous item?
Kurt Milam
@kurtmilam
Apr 20 2017 14:51
@ScottFreeCode an option is Promise.all
Scott Santucci
@ScottFreeCode
Apr 20 2017 14:51
Nope, they should be pretty much isolated.
James Forbes
@JAForbes
Apr 20 2017 14:51
Yeah you should be able to use Promise.all, or Future.parallel etc
depends on the work too
Kurt Milam
@kurtmilam
Apr 20 2017 14:51
Probably similar functionalities in various futures libraries (Fluture, etc).
James Forbes
@JAForbes
Apr 20 2017 14:52
if its e.g. IO, or DB stuff, it will probably be parallel for free
if its stuff within JS itself (not network, or filesystem etc) you'd have to spawn child processes, and its probably not worth it unless its long running
because instantiating a new process has a cost
but node is pretty great at that stuff now, if you do need to go down that road
Scott Santucci
@ScottFreeCode
Apr 20 2017 14:53
Right; it's not an optimization I'd reach for initially, but I want to be reasonably sure I won't have to throw my whole design out if I ever find a need for it...
James Forbes
@JAForbes
Apr 20 2017 14:53
I have this silly Thread helper I use for that
nah it should be easy enough to do that stuff without changing existing code too much
especially if its pure
I've recently done a lot of work with AWS Lambda, and its almost funny how easy it is to fire some code in an entirely new "server"
Kurt Milam
@kurtmilam
Apr 20 2017 14:54
@JAForbes nice to hear your take on Sanctuary types vs Typescript types. Honestly, I've only played with Typescript a little, but I wasn't convinced.
Scott Santucci
@ScottFreeCode
Apr 20 2017 14:54
I'm less concerned with how to get the promises (or tasks/futures) to be used in order and more concerned with, conceptually, if I have to send results back from a bunch of workers, how do I ensure they don't send back the result for the same entry more than once.
James Forbes
@JAForbes
Apr 20 2017 14:54
@kurtmilam yeah typescript is a good fit for different workflows
@ScottFreeCode that would be handled automatically
Kurt Milam
@kurtmilam
Apr 20 2017 14:56
@ScottFreeCode Parallel JS could be interesting if you want to use web workers to parallelize operations.
James Forbes
@JAForbes
Apr 20 2017 14:56
@ScottFreeCode if you have 1 promise per worker, and they just return a value when they're done, they don't (need to) know how to send multiple values, and Promise.all will only ever accept 1 value per promise in the list, it will ignore subsequent ones.
Kurt Milam
@kurtmilam
Apr 20 2017 14:56
Yeah, also if you resolve a Promise twice, it only does the work once.
Scott Santucci
@ScottFreeCode
Apr 20 2017 14:57
Right, it wouldn't really harm anything anyway...
Kurt Milam
@kurtmilam
Apr 20 2017 15:00
I use Promise.all for parallelization of tasks. In my use-case a Promise may be resolved multiple times and some Promises need to wait on others before firing, but resolving multiple times is not an issue and getting them to wait on each other is trivial.
Scott Santucci
@ScottFreeCode
Apr 20 2017 15:01
Maybe I should back up -- where I'm at right now is thinking that I could pass results back using Node's onmessage IPC, but then I have to figure out which promise to resolve with that message. What I'm wondering is, is there a better way to structure this so that the "I have to figure out which promise to resolve to that message" part just isn't there?
Kurt Milam
@kurtmilam
Apr 20 2017 15:01
I create what I call a 'Promise tree' where all Promises at leaf nodes are resolved and all Promises at nodes higher up the tree wait on their 'children' to resolve.
James Forbes
@JAForbes
Apr 20 2017 15:01

@kurtmilam runtime type checking has some interesting consequences, like at first it seems like a hack, but its interesting.

I've got types for behaviour, or for things that are easy to verify at runtime, but hard to represent at compile time.

E.g., this is an even number, or this is a sorted list, or this is a word that contains no vowels

Its really powerful to say "this is a X", and then have the rest of your code just believe you, and not check conditions constantly
And you don't need to wrap your values in special types
e.g. sanctuary has a PositiveNumber type built in
but the runtime requirements is just a js number
and if its is valid, it won't throw an error
Kurt Milam
@kurtmilam
Apr 20 2017 15:04
Nice. Is there any way to extract the requirements for use in, say, real-time form validation?
James Forbes
@JAForbes
Apr 20 2017 15:04
you could do really funny things like have a type that says "this is a ramda function name", or "this is a spanish word" instead of just string
yep, you can manually test types
Kurt Milam
@kurtmilam
Apr 20 2017 15:04
@ScottFreeCode Sorry, I haven't actually worked with web workers or spawning new processes yet.
James Forbes
@JAForbes
Apr 20 2017 15:04
and you can manually get the error message too via an Either (instead of relying on try catches)
Kurt Milam
@kurtmilam
Apr 20 2017 15:05
I'd be off looking for a library and trying to find the answers to the same questions you're asking.
Scott Santucci
@ScottFreeCode
Apr 20 2017 15:05
Okeydokey.
Kurt Milam
@kurtmilam
Apr 20 2017 15:06
Nice. I'm working on a bit of a greenfield project, so I have to figure out which types to define and how to define them.
Is it possible to compose types, like you have a Person type and an Employee type that has all of the attributes of the Person type?
James Forbes
@JAForbes
Apr 20 2017 15:07

@ScottFreeCode I think you want to abstract over the particular keys, and just work with functions that return Promises.

Tell the worker what message you want it to send back as part of your message that you send. You want to abstract over that API as early as possible because its terrible :D

Kurt Milam
@kurtmilam
Apr 20 2017 15:07
And maybe a Manager type which has most of the attributes of of an Employee type but has no heart or soul? :D
James Forbes
@JAForbes
Apr 20 2017 15:07
if possible randomly generate that particular message key at send time
Another approach is to treat it like a client/server model, where you have "endpoints"
so just have a single message that goes to a router and it routes it to the particular handler
Joey Figaro
@joeyfigaro
Apr 20 2017 15:10
hey all
is there anyone who might have some thoughts on combining two arrays of objects into a single array based on matching key values (but different key names)? I have an array of user objects and an array of payment objects. Payment objects have a user key with an ID, and user objects have an id key with the ID.
I'd like a zipped array of user objects where each user has a transactions array - populated with any transactions they've had.
James Forbes
@JAForbes
Apr 20 2017 15:12
@joeyfigaro probably a groupBy on the shared property on both data sets, then a concat/merge whatever you want
@kurtmilam yeah you can compose types, I've been playing with that, still experimental
I'm sure there'd be better ideas if you asked around in that room
Kurt Milam
@kurtmilam
Apr 20 2017 15:14
Indeed. I watch that room but haven't contributed yet.
James Forbes
@JAForbes
Apr 20 2017 15:15
@kurtmilam I've got this helper for Nullary types:

const $or = (a,b) =>
   $.NullaryType(
     [a,b].map( T => T.format(String) ).join(' | ')
     , a.url || b.url
     , x => [a,b].some( T => $.test([], T, x) )
   )

const $and = (a,b) =>
   $.NullaryType(
     [a,b].map( T => T.format(String) ).join(' & ')
     , a.url || b.url
     , x => [a,b].every( T => $.test([], T, x) )
   )
@kurtmilam oh great! You probably saw me musing on this
Kurt Milam
@kurtmilam
Apr 20 2017 15:15
I did! So much to learn!
James Forbes
@JAForbes
Apr 20 2017 15:15
So I've got 2 types, and I want them to both be satisfied:
$and(
    $SortedScheduleVersionList
    ,$LabelList
)
That creates a new type, which sanctuary will render as SortedScheduleVersionList & LabelList
Again, its all runtime, its all js, so really we're just taking 2 data structures and generating a new one
pretty powerful
I can't figure out how to generalize it for non nullary types
Kurt Milam
@kurtmilam
Apr 20 2017 15:16
Cool :thumbsup:
James Forbes
@JAForbes
Apr 20 2017 15:16
but I'm sure its possible
Kurt Milam
@kurtmilam
Apr 20 2017 15:17
I bet you'll figure it out.
James Forbes
@JAForbes
Apr 20 2017 15:17
haha thank you
Joey Figaro
@joeyfigaro
Apr 20 2017 15:17
@JAForbes Beautiful - thanks man.
James Forbes
@JAForbes
Apr 20 2017 15:17
@joeyfigaro my pleasure
@kurtmilam while I'm evangelizing...
Kurt Milam
@kurtmilam
Apr 20 2017 15:18
I do have a moment for you to share with me the miracle of ...
James Forbes
@JAForbes
Apr 20 2017 15:18
@kurtmilam the other great thing worth mentioning about sanctuary, all of its functions are total
So even without the type checking, the workflow is more likely to save you from annoying js undefined bugs
e.g. find is a function I use very often, the fact it returns a maybe means I have to be honest about the fact that technically the list may yield undefined
without sanctuary, sometimes, I may get cocky and think I don't need to do that check
but with sanctuary I don't really have a choice, and that's a good thing
Kurt Milam
@kurtmilam
Apr 20 2017 15:21
Gotcha, and agreed. I'm all too often guilty of leaving out those checks until they bite me.
James Forbes
@JAForbes
Apr 20 2017 15:21
And that's kind of why typescript isn't helpful, or worth the compile time cost I ran into (60s incremental!), because all it gave me was protection from bugs I would never encounter anyway
the jump to declaration stuff, you can do that in js (thanks to the typescript project ironically), and then eslint cover the remaining gap
Kurt Milam
@kurtmilam
Apr 20 2017 15:22
Throw the code together with naive assumptions and wait for it to break to add the necessary checks. I like the idea of forcing that to the forefront.
Yeah, I can jump to declarations in my IDE without any type definitions.
I am looking forward to the day when IDEs are a little smarter about currying, however.
James Forbes
@JAForbes
Apr 20 2017 15:23
yeah, I mean in that edit I say thanks to TS, even though other ide's do it, but TS has made working with JS on its own so much better
automatic type acquisitions for example
@kurtmilam yeah that's one benefit to manual currying, ide's can keep up
Kurt Milam
@kurtmilam
Apr 20 2017 15:24
:thumbsup:
James Forbes
@JAForbes
Apr 20 2017 15:24
it'd be kind of cool to have a single base tsd for all fantasy land projects, just so when we see concat it doesn't give up
Kurt Milam
@kurtmilam
Apr 20 2017 15:25
I've been writing a lot of code that looks like this when working with manually-curried functions:
const thing = doit( arg1 )
                  ( arg2 )
                  ( arg3 )
@JAForbes that'd be great! Wonder if it's possible.
Ryan Stegmann
@rstegg
Apr 20 2017 15:29
is anyone familiar with the optional and know if it's similar/same as the maybe monad?
James Forbes
@JAForbes
Apr 20 2017 15:31
yep same thing
Ryan Stegmann
@rstegg
Apr 20 2017 15:31
gucci
James Forbes
@JAForbes
Apr 20 2017 15:31
I think Java calls it optional, or option as well
Ryan Stegmann
@rstegg
Apr 20 2017 15:32
consistency ftw
is there reasoning for the js community to want to use "maybe"?
James Forbes
@JAForbes
Apr 20 2017 15:33
I think most names in this community either come from clojure or haskell, mostly haskell
I think in F# they call it Result
And Just=Some, and Nothing=None
Ryan Stegmann
@rstegg
Apr 20 2017 15:34
result is Either
Joey Figaro
@joeyfigaro
Apr 20 2017 15:34
@JAForbes How about groupBy for a property that isn't shared? ;) Objects on either side of the comparison will have property A or B which will potentially have matching values. The properties aren't identical.
James Forbes
@JAForbes
Apr 20 2017 15:34
ahh
so is option maybe in F# as well?
yeah seems to be
yeah consistency! :D
@joeyfigaro yeah you can use whatever condition you want, just return a value that will be the key in the grouping
@joeyfigaro something that will aid you in merging
Joey Figaro
@joeyfigaro
Apr 20 2017 15:36
Beautiful - thank ya
James Forbes
@JAForbes
Apr 20 2017 15:36
:sparkles:
Joey Figaro
@joeyfigaro
Apr 20 2017 15:36
You take tips @JAForbes?
James Forbes
@JAForbes
Apr 20 2017 15:37
haha no
alright battery's dying, better sleep, good talking to y'all
Joey Figaro
@joeyfigaro
Apr 20 2017 15:37
Later bud. Thanks again.
Kurt Milam
@kurtmilam
Apr 20 2017 15:40
:wave:
Rory Smith
@alanbuchanan
Apr 20 2017 21:25

hi all, is there a good ramda method that will do the following?

function getFirstIndexOfName(name) {
  const things = {
    1: ['bert'],
    2: ['kent', 'alan'],
    3: ['bert', 'roger'],
    4: ['allan', 'ray', 'john', 'jane'],
    5: ['bert', 'jane', 'ray'],
    6: ['alejandro', 'pete']
  }

  return ...
}

getFirstIndexOfName('bert') // 1
getFirstIndexOfName('kent') // 2
getFirstIndexOfName('ray') // 4

i want to go through all the items in things and return the key of the first occurrence of whatever name is passed in. I wrote this with a combination of a for loop with a break and Object.keys, but I think there are definitely better ways to accomplish this. any ideas?

Brad Compton (he/him)
@Bradcomp
Apr 20 2017 22:08
Is there a reason you're using an object with numeric keys instead of an Array?
Robert Mennell
@skatcat31
Apr 20 2017 22:10
@alanbuchanan http://ramdajs.com/docs/#reduceWhile is probably what you're looking for, but @Bradcomp brings up a very valid point. Why a numerically indexed dictionary instead of an array?
Brad Compton (he/him)
@Bradcomp
Apr 20 2017 22:10
R.findIndex
Brad Compton (he/him)
@Bradcomp
Apr 20 2017 22:11
With an array you could just do that
Robert Mennell
@skatcat31
Apr 20 2017 22:14
forgot Ramda had findIndex.... Used to just using that built into the array itself XD Ah how JS has spoiled me