These are chat archives for ramda/ramda

8th
Mar 2017
Robert Mennell
@skatcat31
Mar 08 2017 00:01
@ram-bot 5 < undefined || 5> undefined
ram-bot
@ram-bot
Mar 08 2017 00:01
false
Robert Mennell
@skatcat31
Mar 08 2017 00:01
seems right to me
@ram-bot undefined == undefined
ram-bot
@ram-bot
Mar 08 2017 00:05
true
Robert Mennell
@skatcat31
Mar 08 2017 00:06
@ram-bot ( undefined < undefined || undefined > undefined ) && undefined == undefined
ram-bot
@ram-bot
Mar 08 2017 00:06
false
Robert Mennell
@skatcat31
Mar 08 2017 00:10
I mean it makes sense. If it's less than an undefined limit...
@laduke
Travis LaDuke
@laduke
Mar 08 2017 00:52
@jonaswindey we shortened your function
Robert Stires
@rjstires
Mar 08 2017 04:10
Was wondering if someone might be able to offer me a little insight. I've been using Ramda for a little bit, but I'm having issues abstracting functions out of the larger masses. I noticed similarities between two functions I mashed together, and felt there had to be a better way. This is a Trello clone for my learning.
let addTaskToBoardWithId = R.curry(
  (boardID, task, boards) => R.map(
    R.when(
      R.propEq('id', boardID),
      R.evolve({tasks: R.append(task)})
    )
  )(boards)
)

let removeTaskFromBoardWithId = R.curry(
  (boardID, taskID, boards) => R.map(
    R.when(
      R.propEq('id', boardID),
      R.evolve({
        tasks: R.filter(R.compose(R.not, R.propEq('id', taskID)))
      })
    )
  )(boards)
)
Brad Compton (he/him)
@Bradcomp
Mar 08 2017 04:45
It looks like you have the makings of an updateTasks function you could use to cover both of these cases.
const updateTasks = curry((f, boardId, boards) => map(
  when(propEq('id', boardId), evolve({tasks: f}))
));

updateTasks(append(newTask), boardId, boards);
updateTasks(reject(propEq('id', taskID)));

//etc.
Of course, you could still create functions for removing and adding tasks, but you now have a general function for modifying the list of tasks for a given board.
Robert Stires
@rjstires
Mar 08 2017 04:47
I thought the same @Bradcomp, my question then was where is taskID coming from in the second updateTasks function there?
Brad Compton (he/him)
@Bradcomp
Mar 08 2017 04:47
It comes from your calling code
same with the newTask above it
Robert Stires
@rjstires
Mar 08 2017 04:48
Would you be able to give me an example? I'm sorry for being so obtuse here.
Brad Compton (he/him)
@Bradcomp
Mar 08 2017 04:48
Sure, lemme go mess about it the repl
Robert Stires
@rjstires
Mar 08 2017 04:49
Thanks, I appreciate that. Still a bit to grasp, both in FP and the library itself.
Brad Compton (he/him)
@Bradcomp
Mar 08 2017 04:55
Robert Stires
@rjstires
Mar 08 2017 04:56
OK so you just essentially write curried wrappers to supply the values? I wasn't sure if there was another preferred way of going about it. Thanks for clearing that up @Bradcomp
Brad Compton (he/him)
@Bradcomp
Mar 08 2017 04:56
No prob...
That's how I would probably do it. Often I will hold off on refactoring until I have at least three examples
Robert Stires
@rjstires
Mar 08 2017 04:57
Yea, I've been known to refactor to early or slow my process considerably to refactor early. I have to shake that.
Bravi
@Bravilogy
Mar 08 2017 10:25
hey guys. I know there's a ramda cookbook. But I wanted to create something similar, but this one would have examples that I had to work on, at work. And also some nice solutions I've come across, to common problems.
So I started this
I will keep adding more and more examples and maybe re-post this link every month or so :D
Stefano Vozza
@svozza
Mar 08 2017 10:58
are you hosting that on hyper.sh?
Aaron Mc Adam
@aaronmcadam
Mar 08 2017 11:02
This is really nice! Thanks @Bravilogy!
Bravi
@Bravilogy
Mar 08 2017 11:07
@svozza it's surge.sh
Adam Szaraniec
@mimol91
Mar 08 2017 11:12
@Bravilogy Nice, I think it should be linked in cookbook
is it opensource?
Bravi
@Bravilogy
Mar 08 2017 11:14
@mimol91 I do have a repo up on github, but it's still work in progress. I will add some more examples, get it into the shape and perhaps we could link it into cookbook too :)
that'd be amazing
Stefano Vozza
@svozza
Mar 08 2017 11:14
@Bravilogy nice!
Adam Szaraniec
@mimol91
Mar 08 2017 11:30
Sorry for silly questions:
There is compose(reduce(or, null), props)(propsToTake, user);
I've always pass 'data' as 2nd argument of compose, so its a little bit unclear how it works.
does it work as
reduce(or, null)(user)( props(prospToTake)) ?
Bravi
@Bravilogy
Mar 08 2017 11:31
not sure if I understand the question correctly, but the first function it will hit will be props, therefore we pass arguments in the same way as props would get them
reduce should receive the extracted props and not the user directly
ah actually I think your example will work
hmm
time for some repl :d
Adam Szaraniec
@mimol91
Mar 08 2017 11:35
How I see it:
(propsToTake, user) this function is passed as argument of props (this is array so I m little bit confuised) and the result of this operation is passed back to reduce(or,null)
Bravi
@Bravilogy
Mar 08 2017 11:35
yeah exactly. reduce expects an array, right? So the result of props will be an array
Adam Szaraniec
@mimol91
Mar 08 2017 11:37

Ye, but

compose(
  reduce(or, null),
  props
)(propsToTake, user);

invoke from bottom to top
so I dont get why its call props(propsToTake, user) - I guess its 1st step of this 'operation'

My mind have just explored, I've always pass object for compose
But <3 this examples
Bravi
@Bravilogy
Mar 08 2017 11:40
you can pass any number of arguments to compose / pipe. compose looks smth like this:
const compose = (...fns) => (...args) => ...
so it accepts any number of arguments and they will all be passed to the first step, in this case - props
Adam Szaraniec
@mimol91
Mar 08 2017 11:41
I've tried with compose(identity)(user, user) and the result was just a 'single' user
Bravi
@Bravilogy
Mar 08 2017 11:41
that's because identity expects 1 argument itself

So imagine something like this

const identity = x => x;

and what you're doing is:

identity(user, user);

therefore the second user is ignored

Adam Szaraniec
@mimol91
Mar 08 2017 11:43
Ahh
compose((...args)=>args)(propsToTake, user) make sense
Bravi
@Bravilogy
Mar 08 2017 11:43
yep
btw, there's a link to repl at the end of every single example
to play around
Adam Szaraniec
@mimol91
Mar 08 2017 12:38
@Bravilogy
Isnt it better?
compose(head, props)(propsToTake, user); ?
Bravi
@Bravilogy
Mar 08 2017 12:40
@mimol91 that will return undefined if firstName is not there
if you get rid of firstName property completely
another solution would be
compose(head, filter(Boolean), props)
Adam Szaraniec
@mimol91
Mar 08 2017 12:44
ahh ye, nice
Bravi
@Bravilogy
Mar 08 2017 12:45
or
compose(head, reject(isNil), props)
dunno.. many different possibilities
Adam Szaraniec
@mimol91
Mar 08 2017 12:47
Found next compose(find(identity), props)(propsToTake, user);
I like it
Bravi
@Bravilogy
Mar 08 2017 12:47
yeah, that one's nice too
Adam Szaraniec
@mimol91
Mar 08 2017 12:48
I think Its good that you show how you can achieve solution, cos there is a lot of funciton which I've never used (like apply) etc, and thanks to this examples I got more knowledge how it works
Bravi
@Bravilogy
Mar 08 2017 12:49
yeah. that's what I've always struggled with when I started ramda. There are so many functions and so many possibilities. I learn new things every day
Bravi
@Bravilogy
Mar 08 2017 13:20
guys, can I make this point free somehow?
(a, b) => compose(a, reduce(or, null), b)
that's the best I could come up with
Vladimir Starkov
@iamstarkov
Mar 08 2017 14:19
hey
Johnny Hauser
@m59peacemaker
Mar 08 2017 16:50
I have a source object with values that may be string or arrays and a destination object that is the same... where destination has existing keys, the values need to be combined (if dest has string, make array and add string from source or concat array from source)
Is there an operator that comes to mind for such a thing?
oh duh, maybe mergeWithKey
Raine Virta
@raine
Mar 08 2017 17:17
@ram-bot R.ascend
ram-bot
@ram-bot
Mar 08 2017 17:17
[Function: f3]
Johnny Hauser
@m59peacemaker
Mar 08 2017 17:26
R.mergeWithKey(
  (k, l, r) => R.pipe(
  R.ifElse(
    R.pipe(R.nth(0), R.is(Boolean)),
    R.nth(0),
    R.pipe(
      R.nth(1),
      R.when(R.is(String), R.of),
      R.append(l)
    )
  )
)([l, r]),
  {env: 'FOO=foo'},
  {env: 'BAR=bar', bool: false}
)
good?
crud, but I need to concat(l) if R.isArrayLike(l)
I work myself into corners like this all the time with Ramda :/
Brad Compton (he/him)
@Bradcomp
Mar 08 2017 17:43
R.cond
Brad Compton (he/him)
@Bradcomp
Mar 08 2017 17:44
@m59peacemaker That might help with the conditional logic you're battling
Johnny Hauser
@m59peacemaker
Mar 08 2017 17:45
mmm.... not sure. It's not the condition so much as it is dealing with nth(0) nth(1)
Brad Compton (he/him)
@Bradcomp
Mar 08 2017 17:45
R.ifElse
Brad Compton (he/him)
@Bradcomp
Mar 08 2017 17:46
Why not just pass in both arguments separately?
Johnny Hauser
@m59peacemaker
Mar 08 2017 17:47
This is the best I have so far and the concat/append are backwards :/
R.mergeWithKey(
  (k, l, r) => R.pipe(
  R.ifElse(
    R.pipe(R.nth(0), R.is(Boolean)),
    R.nth(0),
    R.pipe(
      R.over(R.lensIndex(1), R.when(R.is(String), R.of)),
      R.ifElse(
        R.pipe(R.pipe(R.nth(0), R.isArrayLike)),
        R.apply(R.concat),
        R.apply(R.append)
      )
    )
  )
)([l, r])
If understand your question, I did start that way
It was worse
Brad Compton (he/him)
@Bradcomp
Mar 08 2017 17:49
:(
Johnny Hauser
@m59peacemaker
Mar 08 2017 18:04
const concatOrAppend = (arrayOrString, array) => R.isArrayLike(arrayOrString) ? R.concat(array, arrayOrString) : R.append(arrayOrString, array)
R.mergeWithKey(
  (k, l, r) => R.pipe(
  R.ifElse(
    R.pipe(R.nth(0), R.is(Boolean)),
    R.nth(0),
    R.pipe(
      R.over(R.lensIndex(1), R.when(R.is(String), R.of)),
      R.apply(concatOrAppend)
    )
  ) 
)([l, r]),
  {env: 'BAR=bar'},//['BAR=bar', 'BAZ=baz']},
  {env: ['FOO=foo'], bool: false}
)
concatOrAppend is not very Ramda-like
and then... a light in my brain
    R.pipe(
      R.map(stringToArray),
      R.reverse,
      R.apply(R.concat)
    )
:)
Piet Vandeput
@piet-v
Mar 08 2017 18:09
hi there, started learning Ramda recently and I've hit a wall making a function more abstract >.<
let isNavBarRoute = R.prop('navBar');
    let getSettings = R.prop('settings');
    let getPermissions = R.prop('permissions');
    let canAccess = R.pipe(getPermissions, this.permissionService.hasSomePermissions);
    let byAccessibleNavbarRoute = R.pipe(getSettings, R.allPass([isNavBarRoute, canAccess]));
    let filterNavbarRoutes = R.filter(byAccessibleNavbarRoute);

    return filterNavbarRoutes(this.router.routes);
the code I'm trying to replace by reference
 return this.router.routes
      .filter(route => route.settings.navBar && this.permissionService.hasSomePermissions(route.settings.permissions));
I'd like to abstractify the byAccessibleNavbarRoute function by dynamically replacing the isNavBarRoute with any given function
but I don't know how :(
so that I can call f.e. filterControlPanelRoutes(this.router.routes) which would use isControlPanelRoute
Johnny Hauser
@m59peacemaker
Mar 08 2017 18:22
@piet-v I'd help you if I could. I'm a noob myself.
Piet Vandeput
@piet-v
Mar 08 2017 18:22
rip :smile:
Johnny Hauser
@m59peacemaker
Mar 08 2017 18:24
So... here it is in the extremest form I could go. Is this good or too far?
R.mergeWithKey(R.pipe(
  R.unapply(R.slice(1, 3)),
  R.ifElse(
    R.pipe(R.nth(0), R.is(Boolean)),
    R.nth(0),
    R.pipe(R.map(R.when(R.is(String), R.of)), R.reverse, R.apply(R.concat))
  ) 
)
I can read that now, but 1. I wrote it and 2. I just wrote it.
Piet Vandeput
@piet-v
Mar 08 2017 18:26
split it up in subfunctions, who knows when/where u can reuse em?
Ferdinand Salis
@ferdinandsalis
Mar 08 2017 18:28
@m59peacemaker very hard to follow for me :)
but I am also pretty new to ramda and fp
why dont you split it up a bit and give it some descriptive names?
at least thats what I would do and when I would come back to it I would still understand it :)
Piet Vandeput
@piet-v
Mar 08 2017 18:30
splitting it up might (read: will) improve ur changes to debug it if u ever need to in the future lol
Johnny Hauser
@m59peacemaker
Mar 08 2017 18:31
only the when part makes sense to be split out
Ferdinand Salis
@ferdinandsalis
Mar 08 2017 18:32
I think it also aids in refactoring, mental model and what not
Piet Vandeput
@piet-v
Mar 08 2017 18:34
and not screwing ur fellow coders over when they have to figure this out x)
Johnny Hauser
@m59peacemaker
Mar 08 2017 18:42
what the heck?!
const x = [['b', 'c'], ['a']]
R.reduceRight(R.concat, [], x)
same result as R.reduce(R.concat, [], x)
Denis Stoyanov
@xgrommx
Mar 08 2017 18:43
@ram-bot
const x = [['b', 'c'], ['a']]
R.reduceRight(R.concat, [], x)
ram-bot
@ram-bot
Mar 08 2017 18:43
[ 'b', 'c', 'a' ]
Denis Stoyanov
@xgrommx
Mar 08 2017 18:44
@ram-bot
const x = [['b', 'c'], ['a']]
R.reduce(R.concat, [], x)
ram-bot
@ram-bot
Mar 08 2017 18:44
[ 'b', 'c', 'a' ]
Denis Stoyanov
@xgrommx
Mar 08 2017 18:44
interesting =)
Robert Mennell
@skatcat31
Mar 08 2017 18:45
@ram-bot R.reduceRight(R.add, '', [1, 2, 3, 4])
ram-bot
@ram-bot
Mar 08 2017 18:45
10
Johnny Hauser
@m59peacemaker
Mar 08 2017 18:52
How can that be?
bug?
Denis Stoyanov
@xgrommx
Mar 08 2017 18:53
javascript :smile:
there are some subtle differences
Johnny Hauser
@m59peacemaker
Mar 08 2017 18:53
@ram-bot R.reduceRight(R.multiply, 1, [2, 3, 4])
ram-bot
@ram-bot
Mar 08 2017 18:54
24
Johnny Hauser
@m59peacemaker
Mar 08 2017 18:54
@ram-bot R.reduce(R.multiply, 1, [1, 2, 3])
ram-bot
@ram-bot
Mar 08 2017 18:54
6
Robert Mennell
@skatcat31
Mar 08 2017 18:55
@ram-bot R.reduceRight(console.log, '', [1,2,3])
ram-bot
@ram-bot
Mar 08 2017 18:55
console is not defined
okay fine
when you run that repl you'll see it operates in reverse order
better example, has reduce and reduceRight
Johnny Hauser
@m59peacemaker
Mar 08 2017 19:01
@ram-bot [[1], [2]].reduceRight(R.concat)
ram-bot
@ram-bot
Mar 08 2017 19:01
[ 2, 1 ]
Johnny Hauser
@m59peacemaker
Mar 08 2017 19:03
ahhh
imo, R.concat is wrong.
It's backwards.
not cool, man
Robert Mennell
@skatcat31
Mar 08 2017 19:06
@ram-bot [[1], [2], [3]].reduce(R.concat)
ram-bot
@ram-bot
Mar 08 2017 19:06
[ 1, 2, 3 ]
Robert Mennell
@skatcat31
Mar 08 2017 19:06
@ram-bot [[1], [2], [3]].reduceRight(R.concat)
ram-bot
@ram-bot
Mar 08 2017 19:06
[ 3, 2, 1 ]
Johnny Hauser
@m59peacemaker
Mar 08 2017 19:07
R.concat should take (last, first)
R.concat(addingThis)(toThis)
Denis Stoyanov
@xgrommx
Mar 08 2017 19:09
@ram-bot R.concat([1], [2])
ram-bot
@ram-bot
Mar 08 2017 19:09
[ 1, 2 ]
Denis Stoyanov
@xgrommx
Mar 08 2017 19:09
@ram-bot R.concat([2], [1])
ram-bot
@ram-bot
Mar 08 2017 19:09
[ 2, 1 ]
Robert Mennell
@skatcat31
Mar 08 2017 19:09
this is one of those places where the reverse order doesn't make much sense IMO. The thing you'd add, would be what you get later, more like R.concat( have )( given )
Johnny Hauser
@m59peacemaker
Mar 08 2017 19:10
Not in my case, at least..
I guess either is fair play
but that could kinda always be the case
Piet Vandeput
@piet-v
Mar 08 2017 19:11
can always use R.flip
Robert Mennell
@skatcat31
Mar 08 2017 19:11
^^^
Piet Vandeput
@piet-v
Mar 08 2017 19:12
find the flipped params of the reduceRight way tricker T.T
Robert Mennell
@skatcat31
Mar 08 2017 19:15
I've noticed the pattern I use a lot is fn(known)(unknown)
Piet Vandeput
@piet-v
Mar 08 2017 19:15
isn't that what the autocurrying prefers?
Johnny Hauser
@m59peacemaker
Mar 08 2017 19:16
well, way back to my code earlier, here is a more readable version
const stringToArray = R.when(R.is(String), R.of)
const concatRight = R.flip(R.concat)
R.mergeWithKey(R.pipe(  // this is going to happen when the destination object already has a key
  R.unapply(R.slice(1, 3)), // (k, l, r) => [l, r]
  R.ifElse(
    R.pipe(R.nth(0), R.is(Boolean)),
    R.nth(0), // return "l" if it is a boolean
    R.pipe(R.map(stringToArray), R.apply(concatRight)) // turn "l" and "r" strings into arrays and then add "l" to the end of "r"
  ) 
))
Piet Vandeput
@piet-v
Mar 08 2017 19:17
seems readable :)
anyone here knowledgeable of Ramda-Fantasy?
Denis Stoyanov
@xgrommx
Mar 08 2017 19:19
what about?
Piet Vandeput
@piet-v
Mar 08 2017 19:21
need to call permissionService.hasPermissionToAccess() and was wondering which type to wrap it in
I thought about using IO considering the function I'm calling isn't pure?
Markus Pfundstein
@MarkusPfundstein
Mar 08 2017 21:39
if its async, use a Task?
Vladimir Starkov
@iamstarkov
Mar 08 2017 23:23
hey
i need some help
const input = {
  a: Promise.resolve(true),
  b: Promise.resolve(true),
}

const output = {
  a: true,
  b: true,
}
cons fn = R.pipeP(/* ? */);

fn(input); // output
i dont know how to write this
i tried this
const asyncValues = R.pipeP(...[
  R.values,
  promiseAll,
]);

const fn = R.pipeP(...[
  R.unapply(R.ap([R.keys, asyncValues]))
  promiseAll,
  R.zipObj,
]);
but instead of promiseAll in fn i think i need to do two things
Piet Vandeput
@piet-v
Mar 08 2017 23:29
doesn't pipeP always return a promise?
Vladimir Starkov
@iamstarkov
Mar 08 2017 23:30
yes
but i solved it
thanks
Piet Vandeput
@piet-v
Mar 08 2017 23:30
isn't this basically Promise.all() in some libraries? :D
Vladimir Starkov
@iamstarkov
Mar 08 2017 23:30
mm?
Promise.all works on arrays
not on object
Piet Vandeput
@piet-v
Mar 08 2017 23:31
in some it works on object too
think in $q or bluebird, forgot which
Vladimir Starkov
@iamstarkov
Mar 08 2017 23:31
there is BluebirdPromise.props, which works this way
but i dont want bluebird
Piet Vandeput
@piet-v
Mar 08 2017 23:32
ok ^^
@iamstarkov just checked, it was the angular $q library that accepts objects if u ever need it :D
Vladimir Starkov
@iamstarkov
Mar 08 2017 23:35
nah
angular contains to much magic for my small brain
but anyhow, thanks for suggestion
Piet Vandeput
@piet-v
Mar 08 2017 23:35
can't argue with the magic part <.<
on other hand ramda can be too
Vladimir Starkov
@iamstarkov
Mar 08 2017 23:36
ramda is just 239 pure functions
239, omg
Raine Virta
@raine
Mar 08 2017 23:53
@skatcat31 I added console.log to ram-bot
@ram-bot R.reduceRight(console.log, '', [1,2,3])
ram-bot
@ram-bot
Mar 08 2017 23:54
undefined

output

3
2
1
Robert Mennell
@skatcat31
Mar 08 2017 23:54
sweet
@raine I like the example BTW :wink: