These are chat archives for ramda/ramda

1st
Aug 2016
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 13:40 UTC
Hi everyone, given the following composition, I need to pick off some keys of the data structure and pipe it through to the rest of the composition:
const buildComparison = R.compose(
  compact,
  R.apply(R.lift(matchImage)),
  R.pluck('images’),
  // I need to pick off a `title` property of each object here and join it with the output of the following `matchImage` mapping
  R.props(['taskLeft', 'taskRight'])
);
Is there a way I can pass-through some data and combine it at the end? I suppose the simplest thing to do is just to have a separate composition to get the object I need and then merge them together?
James Forbes
@JAForbes
Aug 01 2016 13:45 UTC
@aaronmcadam you probably want to try using R.converge, but its often cleaner to just give up on point free in these situations
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 13:45 UTC
yeah, I did think of converge, but I’m not 100% sure on how it works
thanks though @JAForbes :)
hemanth.hm
@hemanth
Aug 01 2016 13:46 UTC
looking for a better way to do R.head(R.keys(R.head(x)))
let x = [ { eligibility: true } ]
James Forbes
@JAForbes
Aug 01 2016 13:49 UTC

@aaronmcadam I think the converge examples make it seem harder than it is.

R.converge(R.concat, [R.toUpper, R.toLower])('hello')

Without posting the output, what do you think it will be? Just take a guess

Aaron Mc Adam
@aaronmcadam
Aug 01 2016 13:50 UTC
‘helloHELLO’?
or upper first?
James Forbes
@JAForbes
Aug 01 2016 13:50 UTC
upper first
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 13:50 UTC
Hmm
James Forbes
@JAForbes
Aug 01 2016 13:50 UTC
but pretty simple right?
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 13:51 UTC
yah
James Forbes
@JAForbes
Aug 01 2016 13:51 UTC
I think we need to purge maths from the code examples
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 13:52 UTC
hah probably, more tangible examples work better
How would my example use converge? I’m trying it now. If I break up the composition that builds my images
James Forbes
@JAForbes
Aug 01 2016 13:53 UTC

R.converge(multiply, [add, subtract])(1, 2); //=> 3 expects to compute all the possible assumptions in your head to prove or disprove your understanding

And because its just numbers its hard to assume the intent.

But with that concat example, its fairly obvious that that function combines the results from the array of functions. The only thing left to guess is the order.

Aaron Mc Adam
@aaronmcadam
Aug 01 2016 13:54 UTC
yeah, which is left to right here
the tricky part of my composition is that I only want to add data from taskLeft and taskRight if there’s a matching image...
hemanth @hemanth sits at a corner
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 13:57 UTC
actually, that’s not quite true, I still need the some props of the task that’s being compared. I think I’ll have to map this separately after all
Denis Stoyanov
@xgrommx
Aug 01 2016 14:14 UTC
@aaronmcadam what is a problem?)
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 14:15 UTC
I wasn’t quite thinking about my problem properly
I’m building a table structure from a prepatory-step structure
I need the title of both the left Task and the right Task so I can build an array of headers
{ 
  header: { 
    label: ‘left task title’
  }, 
  cell:  {
    property: ‘leftImageResonance’
  }
}
So I’ll have a rows object that the existing composition can be added to, and a headers object for the above
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 15:23 UTC
ya so now I’ve got this, I’m thinking I’d like to compose it:
const buildTable = (tasks) => {
  const comparedTasks = R.zipObj(['leftTask', 'rightTask'], tasks);

  return {
    columns: buildColumns(comparedTasks),
    rows: buildComparison(comparedTasks)
  };
};
Brad Compton (he/him)
@Bradcomp
Aug 01 2016 15:26 UTC
@hemanth Better in what way? That looks like a good solution if you can assume the object only has one key.
Denis Stoyanov
@xgrommx
Aug 01 2016 15:29 UTC
const buildTable  = compose(converge(unapply(zipObj(['columns', 'rows'])), [buildColumns, buildComparison]), zipObj(['leftTask', 'rightTask']))
But I don't test it
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 15:30 UTC
wow, thanks for all the help @xgrommx!
Denis Stoyanov
@xgrommx
Aug 01 2016 15:30 UTC
@aaronmcadam I fixed it =)
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 15:31 UTC
Cheers!
hemanth.hm
@hemanth
Aug 01 2016 15:40 UTC
@Bradcomp making it shorter, if the array has objects with just a key, I could map over them...hmm
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 15:45 UTC
Thanks @xgrommx, @JAForbes. I think I understand converge better now!
James Forbes
@JAForbes
Aug 01 2016 15:47 UTC
:D
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 15:49 UTC
I definitely think your concat example should be added to the docs tho!
Denis Stoyanov
@xgrommx
Aug 01 2016 15:50 UTC
@aaronmcadam converge is just sequence + apply(fn)
@aaronmcadam or another way it's some using applicative functor
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 15:51 UTC
I need to re-read my book on FP :)
@aaronmcadam my implementation of converge via applicative functor https://github.com/xgrommx/from-combinators-to-fp/blob/master/src/index.js#L26
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 15:53 UTC
Does anybody use Promise.all in a point-free way?
Brad Compton (he/him)
@Bradcomp
Aug 01 2016 15:54 UTC
@aaronmcadam I do, but you need to bind the context... Promise.all.bind(Promise)
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 15:54 UTC
const buildComparisonTable = (projectId, taskIds) => (
  R.composeP(
    buildTable,
    R.map(mapComparisonTask),
    () => Promise.all(getImages(projectId, taskIds))
  )()
);
Seems to work, but Promise.all on its own doesn’t. yeah thought it might be a this problem :)
Denis Stoyanov
@xgrommx
Aug 01 2016 15:55 UTC
@aaronmcadam Promise.all is a just sequence for Promise if Promise.of = Promise.resolve
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 15:55 UTC
How do you call the catch for catching errors?
Brad Compton (he/him)
@Bradcomp
Aug 01 2016 15:56 UTC
@hemanth map works on objects too if it helps. So if you want to operate on the values of the object, you can do map(map(f))(objArray)
hemanth.hm
@hemanth
Aug 01 2016 15:57 UTC
@Bradcomp Nice.
Brad Compton (he/him)
@Bradcomp
Aug 01 2016 15:57 UTC
const catch = curry((f, p) => p.catch(f));
Although that may not work due to catch being reserved
hemanth.hm
@hemanth
Aug 01 2016 15:57 UTC
Quick questions, how many of you use combinators in daily programming?
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 15:57 UTC
ya but where do you put it in your composition?
hemanth.hm
@hemanth
Aug 01 2016 15:58 UTC
there is a proposal for Promise.finally
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 15:58 UTC
@hemanth that’s my next step after using composition for a week or two
I’m going to start using Maybe and Either types next
hemanth.hm
@hemanth
Aug 01 2016 15:59 UTC
@aaronmcadam Cool
Brad Compton (he/him)
@Bradcomp
Aug 01 2016 15:59 UTC
@hemanth I don't use combinators in the sense of the upper case letter combinators, but I do use functions that could be considered as combinators
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 15:59 UTC
I’m still practicing point-free style though too
Denis Stoyanov
@xgrommx
Aug 01 2016 15:59 UTC
this is standard behaviour for functor of functors. fmap (fmap(*10)) [Just 10, Just 20, Just 30]
hemanth.hm
@hemanth
Aug 01 2016 16:00 UTC
point-free, ain't pointless ;)
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 16:00 UTC
const buildComparisonTable = R.composeP(
  buildTable,
  R.map(mapComparisonTask),
  Promise.all.bind(Promise),
  getImages
);
This doesn’t work. Where could I inject a catch?
hemanth.hm
@hemanth
Aug 01 2016 16:00 UTC
@xgrommx Your are in the next level altogether ;)
Denis Stoyanov
@xgrommx
Aug 01 2016 16:00 UTC
@aaronmcadam I think you need Either and probably bifunctor
hemanth.hm
@hemanth
Aug 01 2016 16:01 UTC
I would really be happy to see some review comments, PRs or correction on http://git.io/fp-jargons
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 16:01 UTC
I should be able to build a few promises (returned by getImages), then pass them on for Promise.all to process em, right?
hemanth.hm
@hemanth
Aug 01 2016 16:01 UTC
@aaronmcadam yes, but the order in which they resolve can't be promised
Denis Stoyanov
@xgrommx
Aug 01 2016 16:01 UTC
@aaronmcadam use bind from Ramda
hemanth.hm
@hemanth
Aug 01 2016 16:02 UTC
Promise.all::Promise aye?
Denis Stoyanov
@xgrommx
Aug 01 2016 16:02 UTC
@hemanth easy describing about monads :smile: https://github.com/hemanth/functional-programming-jargon#monad
hemanth.hm
@hemanth
Aug 01 2016 16:02 UTC
(1 > 2 ? Promise.reject : Promise.resolve)('creepy, don\'t work')
@xgrommx Monads is like asking fish to explain water :D
^ bad one?
Brad Compton (he/him)
@Bradcomp
Aug 01 2016 16:05 UTC
@aaronmcadam it depends on whaere you want to catch the error ;-P. Like if you're just doing clean up then put it at the end, or just call catch on the resultant promise
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 16:06 UTC
yeah, I keep getting promises that are never resolved :/
Denis Stoyanov
@xgrommx
Aug 01 2016 16:06 UTC
@aaronmcadam Simple example
let allP = bind(Promise.all, Promise);
let p = compose(allP, map(bind(Promise.resolve, Promise)));

p([10,20,30,40]).then(bind(console.log, console));
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 16:06 UTC
So I’d like to know what the error is during development. I keep having to restart my test suite :worried:
Denis Stoyanov
@xgrommx
Aug 01 2016 16:08 UTC
@hemanth Monads is the abstract value. We need know how it works in implementation of monad for array, maybe and etc. But in general it is math.
hemanth.hm
@hemanth
Aug 01 2016 16:08 UTC
👌
Brad Compton (he/him)
@Bradcomp
Aug 01 2016 16:09 UTC
If you're using mocha, just put the catch at the end and pass in done
  promiseReturning(input)
     .then(output => {
           expect(output).to.be(/*stuff*/)
           done();
}).catch(done)
James Forbes
@JAForbes
Aug 01 2016 16:10 UTC
@Bradcomp apologies if I am missing some context, but in mocha, you can just return the promise, you don't need done
Brad Compton (he/him)
@Bradcomp
Aug 01 2016 16:11 UTC
Oh yeah... I keep forgetting that
For some reason that never sticks in my head
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 16:12 UTC
I don’t need to do that with AVA
I just whack a simple aync in there
the problem really is my route handlers
They return a promise which the Express routes use to then(data => res.json(data)
So, if the promise never resolves, the middleware is stuck waiting until it times out :/
James Forbes
@JAForbes
Aug 01 2016 16:14 UTC
@Bradcomp Same happened to me
Brad Compton (he/him)
@Bradcomp
Aug 01 2016 16:22 UTC
I've started separating my route handlers into separate functions, and then returning the promise from the handler. It makes life easier for testing, and keeps the route files more readable
Then you can call .catch() on the handler itself to catch any assertion errors
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 16:28 UTC
Do I need a catch in my route definition?
Brad Compton (he/him)
@Bradcomp
Aug 01 2016 16:30 UTC
Well, probably. If something fails as it is right now, no response will be sent.
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 16:31 UTC
yeah, that must be it
Brad Compton (he/him)
@Bradcomp
Aug 01 2016 16:31 UTC
But, what about just testing fetchComparison directly?
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 16:32 UTC
the functions which compose fetchComparison are all unit tested
then I’m using supertest to integration test the rest
Brad Compton (he/him)
@Bradcomp
Aug 01 2016 16:32 UTC
ah, that makes sense
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 16:33 UTC
I’ve added the test to the gist :)
Brad Compton (he/him)
@Bradcomp
Aug 01 2016 16:34 UTC
Cool! That helps
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 16:34 UTC
Though I do take your point, some of this could well be tested outside of the route-handling
Brad Compton (he/him)
@Bradcomp
Aug 01 2016 16:34 UTC
I would see if it helps to add a catch to the route which sends an error response
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 16:36 UTC
yeah, is there a standard (idiomatic) format I should use?
Brad Compton (he/him)
@Bradcomp
Aug 01 2016 16:38 UTC
I don't know, I haven't looked into it. Here's the function I've used: https://github.com/Bradcomp/egghunt-server/blob/master/routes/helpers.js#L53
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 16:38 UTC
Thanks!!
Brad Compton (he/him)
@Bradcomp
Aug 01 2016 16:38 UTC
then you can do:
.catch(sendError(res))
For work / production I have something more robust so that I don't leak my errors, but that works fine for dev.
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 16:41 UTC
Yeah, I’ve got a branch with winston set up, just haven’t had time to merge it in
hmm
The error isn’t bubbling up to my handler
If I add a catch inside the composeP composition inside the fetchComparison function, I see the error
Tim Navrotskyy
@dypsilon
Aug 01 2016 16:46 UTC
Hi, everyone, I'm learning about free monads right now as a replacement for IO monads. First of all: is it a right thing to do? And second: do you know of any good free monads examples besides the obvious ones by Monet and "Freeky" by Brian?
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 16:47 UTC
Is there a simpler interface I could use here I wonder
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 17:39 UTC
Is there a cleaner (more idiomatic) way to do this?
const getImage = R.map(
  R.pick(['id', 'attributeTitle', 'selected', 'resonance'])
);

/**
 * Extracts a subset of the Task
 * @param {Object} task
 * @returns {Object}
 */
const mapComparisonTask = R.compose(
  R.over(R.lensProp('images'), getImage),
  R.pick(['id', 'title', 'images'])
);
Brad Compton (he/him)
@Bradcomp
Aug 01 2016 18:36 UTC
@aaronmcadam That looks good to me. You could also achieve the same thing using evolve if you're not into lenses
const mapComparisonTask = R.compose(
  R.evolve({images: getImage}),
  R.pick(['id', 'title', 'images'])
);
Denis Stoyanov
@xgrommx
Aug 01 2016 20:07 UTC
yes,evolve nice thing for changing your object
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 20:26 UTC
Nice! Thanks @Bradcomp @xgrommx
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 21:19 UTC
Can anybody recommend a good library for building URLs or paths?
Denis Stoyanov
@xgrommx
Aug 01 2016 21:58 UTC
@aaronmcadam I'm not sure, but probably https://medialize.github.io/URI.js/
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 21:59 UTC
Cool thanks, I know it's off topic :smile:
Would you mind reviewing this gist when you have a minute @xgrommx https://gist.github.com/aaronmcadam/06d7a8bee1415016ddf137a74cdc645e
Specifically, the helper functions that are used in the composition pipelines