These are chat archives for ramda/ramda

1st
Aug 2016
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 13:40
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
@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
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
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

@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
‘helloHELLO’?
or upper first?
James Forbes
@JAForbes
Aug 01 2016 13:50
upper first
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 13:50
Hmm
James Forbes
@JAForbes
Aug 01 2016 13:50
but pretty simple right?
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 13:51
yah
James Forbes
@JAForbes
Aug 01 2016 13:51
I think we need to purge maths from the code examples
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 13:52
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

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
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
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
@aaronmcadam what is a problem?)
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 14:15
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
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
@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
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
wow, thanks for all the help @xgrommx!
Denis Stoyanov
@xgrommx
Aug 01 2016 15:30
@aaronmcadam I fixed it =)
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 15:31
Cheers!
hemanth.hm
@hemanth
Aug 01 2016 15:40
@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
Thanks @xgrommx, @JAForbes. I think I understand converge better now!
James Forbes
@JAForbes
Aug 01 2016 15:47
:D
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 15:49
I definitely think your concat example should be added to the docs tho!
Denis Stoyanov
@xgrommx
Aug 01 2016 15:50
@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
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
Does anybody use Promise.all in a point-free way?
Brad Compton (he/him)
@Bradcomp
Aug 01 2016 15:54
@aaronmcadam I do, but you need to bind the context... Promise.all.bind(Promise)
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 15:54
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
@aaronmcadam Promise.all is a just sequence for Promise if Promise.of = Promise.resolve
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 15:55
How do you call the catch for catching errors?
Brad Compton (he/him)
@Bradcomp
Aug 01 2016 15:56
@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
@Bradcomp Nice.
Brad Compton (he/him)
@Bradcomp
Aug 01 2016 15:57
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
Quick questions, how many of you use combinators in daily programming?
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 15:57
ya but where do you put it in your composition?
hemanth.hm
@hemanth
Aug 01 2016 15:58
there is a proposal for Promise.finally
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 15:58
@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
@aaronmcadam Cool
Brad Compton (he/him)
@Bradcomp
Aug 01 2016 15:59
@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
I’m still practicing point-free style though too
Denis Stoyanov
@xgrommx
Aug 01 2016 15:59
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
point-free, ain't pointless ;)
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 16:00
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
@xgrommx Your are in the next level altogether ;)
Denis Stoyanov
@xgrommx
Aug 01 2016 16:00
@aaronmcadam I think you need Either and probably bifunctor
hemanth.hm
@hemanth
Aug 01 2016 16:01
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
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
@aaronmcadam yes, but the order in which they resolve can't be promised
Denis Stoyanov
@xgrommx
Aug 01 2016 16:01
@aaronmcadam use bind from Ramda
hemanth.hm
@hemanth
Aug 01 2016 16:02
Promise.all::Promise aye?
Denis Stoyanov
@xgrommx
Aug 01 2016 16:02
@hemanth easy describing about monads :smile: https://github.com/hemanth/functional-programming-jargon#monad
hemanth.hm
@hemanth
Aug 01 2016 16:02
(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
@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
yeah, I keep getting promises that are never resolved :/
Denis Stoyanov
@xgrommx
Aug 01 2016 16:06
@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
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
@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
👌
Brad Compton (he/him)
@Bradcomp
Aug 01 2016 16:09
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
@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
Oh yeah... I keep forgetting that
For some reason that never sticks in my head
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 16:12
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
@Bradcomp Same happened to me
Brad Compton (he/him)
@Bradcomp
Aug 01 2016 16:22
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
Do I need a catch in my route definition?
Brad Compton (he/him)
@Bradcomp
Aug 01 2016 16:30
Well, probably. If something fails as it is right now, no response will be sent.
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 16:31
yeah, that must be it
Brad Compton (he/him)
@Bradcomp
Aug 01 2016 16:31
But, what about just testing fetchComparison directly?
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 16:32
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
ah, that makes sense
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 16:33
I’ve added the test to the gist :)
Brad Compton (he/him)
@Bradcomp
Aug 01 2016 16:34
Cool! That helps
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 16:34
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
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
yeah, is there a standard (idiomatic) format I should use?
Brad Compton (he/him)
@Bradcomp
Aug 01 2016 16:38
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
Thanks!!
Brad Compton (he/him)
@Bradcomp
Aug 01 2016 16:38
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
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
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
Is there a simpler interface I could use here I wonder
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 17:39
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
@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
yes,evolve nice thing for changing your object
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 20:26
Nice! Thanks @Bradcomp @xgrommx
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 21:19
Can anybody recommend a good library for building URLs or paths?
Denis Stoyanov
@xgrommx
Aug 01 2016 21:58
@aaronmcadam I'm not sure, but probably https://medialize.github.io/URI.js/
Aaron Mc Adam
@aaronmcadam
Aug 01 2016 21:59
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