These are chat archives for ramda/ramda

18th
Oct 2017
scarmarco
@scarmarco
Oct 18 2017 03:26
Hey guys, how can I safe check R.pipe?
Or actually R.split which is giving me the error
Adrian Skierniewski
@AdrianSkierniewski
Oct 18 2017 06:40
this actually works
Adrian Skierniewski
@AdrianSkierniewski
Oct 18 2017 06:50
I used map instead head to be able to work on multiple roots but then I have additional array around all those paths for particular root. How can I flatten just one array level?
R.apply(R.concat)
Adrian Skierniewski
@AdrianSkierniewski
Oct 18 2017 07:02
but then it doesn't work if I have single array because concat needs at least 2 arrays
Syaiful Bahri
@syaiful6
Oct 18 2017 07:07
@AdrianSkierniewski fold = xss => R.reduce(R.concat, [], xxs)
Adrian Skierniewski
@AdrianSkierniewski
Oct 18 2017 07:08
oh thx
Syaiful Bahri
@syaiful6
Oct 18 2017 07:08
it will flatten one level regardes how many items available in your array
Adrian Skierniewski
@AdrianSkierniewski
Oct 18 2017 07:09
nice
Kurt Milam
@kurtmilam
Oct 18 2017 07:09
Try R.chain(allPaths) in the pipe, as well.
By the way, @syaiful6 helped me with the original allPaths :)
Adrian Skierniewski
@AdrianSkierniewski
Oct 18 2017 07:11
R.chain works too
:)
Kurt Milam
@kurtmilam
Oct 18 2017 07:11
:+1:
Adrian Skierniewski
@AdrianSkierniewski
Oct 18 2017 07:16
in tests everything works, but in real live scenario I'm getting some errors like Cannot read property 'fantasy-land/map' of undefined from doLogs probably because real data sometimes doesn't have the same number of levels in that tree
I'll try to add some condition to check that case
Kurt Milam
@kurtmilam
Oct 18 2017 07:26
I tested with data that had one, two and three levels, and the recent solution worked.
Adrian Skierniewski
@AdrianSkierniewski
Oct 18 2017 07:27
hmm I'm debugging it right now
yes but what if you specified path for 3 levels and one level doesn't exist?
Kurt Milam
@kurtmilam
Oct 18 2017 07:28
it works when I try
Adrian Skierniewski
@AdrianSkierniewski
Oct 18 2017 07:29
ok so it must be something else
maybe in that json
checking it right now
Kurt Milam
@kurtmilam
Oct 18 2017 07:29
The first results from my recent test: [[10], [11, 42], [12, 42, 101, 3847]...
Maybe I need to add the one level in between and test that.
[[9], [10, 42], [11, 42, 101], [12, 42, 101, 3847]... Seems to work fine.
Adrian Skierniewski
@AdrianSkierniewski
Oct 18 2017 07:32
I'm not using this directly on node so it could be something not related
it's some kind of javascript engine inside GO load testing framework, don't even ask why :D
and I saw a lot of different things there, so maybe it's a false alarm
Fortunately I have tests in node + mocha so I'll dump that response to file and then try it directly in node
Kurt Milam
@kurtmilam
Oct 18 2017 07:34
:+1:
Adrian Skierniewski
@AdrianSkierniewski
Oct 18 2017 07:46
ok I recreated issue based on that JSON response, digging deeper what is going on there
ok, so sometimes we don't have that last element
x => R.map(x => [x.id])(R.path(hd, x))
I should probably check if that path exists first, before running that map on it
Adrian Skierniewski
@AdrianSkierniewski
Oct 18 2017 07:53
something ugly as this : x => R.map(x => [x.id])(!R.isNil(R.path(hd, x)) ? R.path(hd, x) : [])
or I can use pathOr
const doLogs =
  ([hd, ...tl]) => {
    return R.map(R.juxt([
      R.prop('id'),
      tl.length > 0
        ? x => doLogs(tl)(R.path(hd, x))
        : x => R.map(x => [x.id])(R.pathOr([], hd, x))
    ]))
  }
Kurt Milam
@kurtmilam
Oct 18 2017 07:59
I was going to suggest something like that. My simulated data with missing levels probably doesn't match the real data exactly.
In my simulation, results was always an array, either empty or not.
Kurt Milam
@kurtmilam
Oct 18 2017 08:07
@AdrianSkierniewski pathOr needs to be here: doLogs(tl)(R.pathOr([], hd, x))
Adrian Skierniewski
@AdrianSkierniewski
Oct 18 2017 08:08
right
and now it will even work for one additional level that is in that JSON
Kurt Milam
@kurtmilam
Oct 18 2017 08:08
nice
Adrian Skierniewski
@AdrianSkierniewski
Oct 18 2017 08:09
I was just ignoring it because it's totalny optional
required => required => required => optional => optional
Kurt Milam
@kurtmilam
Oct 18 2017 08:10
That's a nice thing about a recursive solution - it can deal with varying numbers of levels in the structure.
Adrian Skierniewski
@AdrianSkierniewski
Oct 18 2017 08:12
yes, but it's harder to understand how it work jut by looking at it :)
result from this functions have more that 3k items
now I just need to make some assertions to double check that specific paths are in result
Kurt Milam
@kurtmilam
Oct 18 2017 08:18
Yeah, thinking recursively is also hard on my brain. Some people seem to have a real talent for it. This exercise (and thinking about how easy @syaiful6 seems to find thinking in terms of recursion) has me wondering how much it's a skill that can be trained and how much of it is natural talent.
I'm hoping it's a skill that can be trained, and that I'm not too old too improve in that area :D
Adrian Skierniewski
@AdrianSkierniewski
Oct 18 2017 08:20
me too, I'm always avoiding to use recursion to have code that is easier to understand
but in some cases, like tree structure with n levels, it's a prefect solution
Kurt Milam
@kurtmilam
Oct 18 2017 08:23
:+1:
Adrian Skierniewski
@AdrianSkierniewski
Oct 18 2017 08:24
everything works as expected, all tests are green
Kurt Milam
@kurtmilam
Oct 18 2017 08:24
Awesome!
Adrian Skierniewski
@AdrianSkierniewski
Oct 18 2017 08:25
@kurtmilam Thank you very much. This is one more time when you helped me with figuring out how to do something better using fp approach.
Kurt Milam
@kurtmilam
Oct 18 2017 08:26
The next interesting exercise would be to try to merge the two functions so you didn't have to traverse the data twice.
Adrian Skierniewski
@AdrianSkierniewski
Oct 18 2017 08:26
yes
Kurt Milam
@kurtmilam
Oct 18 2017 08:26
You're welcome! Glad I could help.
Adrian Skierniewski
@AdrianSkierniewski
Oct 18 2017 08:26
but for now it'd be too much magic happen in one function
these two function I understand and I need to get use to how to mix all those function to don't repet my self every time
Kurt Milam
@kurtmilam
Oct 18 2017 08:29
:+1:
AKT
@itsakt
Oct 18 2017 08:35
Hello, need a help. I would like to get the object with min value for one of its properties.
for eg. [{id:1,...},{id:4,...},{id:3,...},...] assume id is the property i'm interested in. The result would be {id:1,...}
Kurt Milam
@kurtmilam
Oct 18 2017 08:45
@itsakt REPL
const getObjWithLowestId =
  o( head )
   ( sortBy( prop( 'id' ) ) )

getObjWithLowestId([{id:5},{id:4},{id:3},{id:2},{id:1}])
// -> {id:1}
Philipp Wille
@Yord
Oct 18 2017 09:01
@itsakt An alternative solution without sort could be:
const obj = [{id:10},{id:2},{id:3}]

const minByProp = propName =>
  reduceRight(
    uncurryN(2)(
      o(min, prop(propName))
    ),
    Number.POSITIVE_INFINITY
  )

const findMinByProp = propName =>
  converge(find)([
    o(propEq(propName), minByProp(propName)),
    identity
  ])

findMinByProp('id')(obj) // {"id":2}
Kurt Milam
@kurtmilam
Oct 18 2017 09:09
I wonder whether that would have any performance advantage over the sortBy variant.
I assume it would have an advantage in terms of required memory, but at worst you're traversing the data twice (reduceRight followed by find if the matching element happens to be the last in the list).
Philipp Wille
@Yord
Oct 18 2017 09:15

While I did not claim it does have a performance advantage, it actually does if I analyze it now:

It has a complexity of O(n) (it runs through any input array exactly twice in the worst case), whereas a sorting algorithm has a complexity of about O(n*log(n)).

(I may be mistaken here, just crunching numbers over lunch ;))

Kurt Milam
@kurtmilam
Oct 18 2017 09:23
I did not claim that you had claimed that it had a performance advantage :D
Philipp Wille
@Yord
Oct 18 2017 09:28
Did I claim that you claimed I claimed that it had a performance advantage? ;) Oh gosh, I guess I did :p
No offense meant by that, though ;) And in my code I would prefer your solution anyway since it is way shorter and more declarative
Kurt Milam
@kurtmilam
Oct 18 2017 09:32
You didn't claim that I claimed that you claimed that I claimed... Oh, you know :D I guess it would be possible to use a more efficient sort algorithm than JavaScript's default as long as we knew the type of the values to be compared.
AKT
@itsakt
Oct 18 2017 09:33
:smile:
Kurt Milam
@kurtmilam
Oct 18 2017 09:33
I asked the original question out of genuine curiousity because I had already been considering whether there might be a more efficient solution that didn't involve creating a new structure just to pick off the structure's head :)
Vesa Karvonen
@polytypic
Oct 18 2017 09:34
Sorting will be slower than a single reduce pass over the elements.
Kurt Milam
@kurtmilam
Oct 18 2017 09:35
@polytypic here we have a single reduce pass followed by a find operation on the original structure.
Vesa Karvonen
@polytypic
Oct 18 2017 09:35
It is unnecessary to make two passes.
Alastair Hole
@afhole
Oct 18 2017 09:36

@afhole see webpack/webpack#5435

@kedashoe A belated thank you :) (I have been in China and brought back a cold :( )

Kurt Milam
@kurtmilam
Oct 18 2017 09:36
@polytypic I figured that was the case. We're talking about the actual implementations provided above.
Maybe I should have approached the problem from that angle: how to get rid of the find operation so you're only iterating over the data once. Note: I'm confident I could figure this out on my own quickly, so it's not really a question like 'how in the world could this be accomplished?' :D
Vesa Karvonen
@polytypic
Oct 18 2017 09:38
Yeah... Incidentally Partial Lenses directly provides a minimumBy fold over traversals that let's you handle a case like this easily.
The way to avoid the second pass is to properly lift from min to minBy to use as the operation to reduce with.
Kurt Milam
@kurtmilam
Oct 18 2017 09:39
I've been thinking about providing solutions to questions here using partial.lenses, in addition to purely Ramda solutions.
:+1: I figured minBy would play a role. I'd also be interested in learning more about the consing technique you're using for local mutation.
You mentioned it in a recent Ramda issue.
Philipp Wille
@Yord
Oct 18 2017 09:46
@kurtmilam I completely misunderstood you there :D Sorry about that, not being English does funny things with you while comprehending texts :p

@polytypic With Ramda's minBy that would be

const obj = [{id:10},{id:2},{id:3}]

const findMinByProp = propName => converge(
  reduce(minBy(prop(propName))),
  [head, tail]
)

findMinByProp('id')(obj)

So basically the same. Did not know minBy even existed until now

Kurt Milam
@kurtmilam
Oct 18 2017 09:48
No worries. Passiert mir auch manchmal, obwohl ich ein Native Englisch Sprecher bin :)
Philipp Wille
@Yord
Oct 18 2017 09:49
Und wieder als Deutscher ertappt ;) Hoffentlich nicht am schlechten Humor :D
Kurt Milam
@kurtmilam
Oct 18 2017 09:49
I also didn't know minBy existed in Ramda, but had made a mental note to look for it (before polytypic mentioned it, even) :D
Es steht in deinem GitHub Profil, dass du in Braunschweig bist ;)
Vesa Karvonen
@polytypic
Oct 18 2017 09:50
Note that tail will make a copy of the array. So, a solution using tail actually makes two passes over the array.
Vesa Karvonen
@polytypic
Oct 18 2017 10:00
BTW, here is a low hanging fruit for some optimization in assocPath. The slice call roughly doubles the amount of allocations that assocPath performs. The recursive calls through a curried function are also very expensive.
Kurt Milam
@kurtmilam
Oct 18 2017 10:02
Parameterized without copying the array:
const getObjWithMinProp =
  propName =>
    R.reduce( R.minBy( prop(propName) ), { [propName]: Infinity } )

getObjWithMinProp('id')([{id:5},{id:4},{id:3},{id:2},{id:1}])
Kurt Milam
@kurtmilam
Oct 18 2017 10:08
@polytypic How would you improve the issue with slice, and by 'curried function', do you specifically mean 'function curried Ramda style'?
Or would that comment also apply to a manually-curried function? Have you compared the impact Ramda-style currying has on performance to the impact of manual currying?
Vesa Karvonen
@polytypic
Oct 18 2017 10:11
Straight R.minBy also works - might be by accident depending on how minBy is implemented.
Kurt Milam
@kurtmilam
Oct 18 2017 10:13
interesting
I assume that will be the fastest purely Ramda implementation we've seen, so far.
Vesa Karvonen
@polytypic
Oct 18 2017 10:15
I would avoid the slice completely and address the array with an index. I'd either remove the recursion completely or move the recursion outside of the curried function (curried non-recursive wrapper and ordinary recursive worker function).
Kurt Milam
@kurtmilam
Oct 18 2017 10:30
:+1:
Seems similar to the rule that one shouldn't create a function in a loop?
Vesa Karvonen
@polytypic
Oct 18 2017 10:40
Well, hand performing loop-invariant code motion can be beneficial in JS and especially so if it saves allocations (like allocating a closure).
Kurt Milam
@kurtmilam
Oct 18 2017 10:44
:+1: I generally try to follow this practice.
Fred Daoud
@foxdonut
Oct 18 2017 12:32
Does Ramda have a function for something along the lines of (f, args) => () => f(args)?
James Forbes
@JAForbes
Oct 18 2017 12:39
http://ramdajs.com/docs/#partial I think is sort of that
if you wanted f(...args)

Oh and mix that in with K, I missed that! :D

Yeah I don't think there's a built in like that

Fred Daoud
@foxdonut
Oct 18 2017 12:47
Actually R.partial does what I want, thanks @JAForbes !
James Forbes
@JAForbes
Oct 18 2017 12:49
ah nice!
Robert Mennell
@skatcat31
Oct 18 2017 16:19
Why not use identity ala R.identity(f(args)) ?
Kurt Milam
@kurtmilam
Oct 18 2017 16:31
@skatcat31 that won't behave the same as the example in the original question. In your solution, f(args) will be executed immediately (and only once).
const later = (f, args) => () => f(args) // f(args) hasn't been executed yet
later() // f(args) has been executed once
later() // f(args) has been executed twice
Robert Mennell
@skatcat31
Oct 18 2017 16:33
@kurtmilam ah I must have missed that they wanted side effects or state of function
Kurt Milam
@kurtmilam
Oct 18 2017 16:34
No worries. I know @foxdonut works a lot with observables, so I immediately figured the delayed & multiple execution was probably something he needed.
Robert Mennell
@skatcat31
Oct 18 2017 16:35
Now the interesting part would be if they wanted a context too, then it'd be partial(bind(fn,ctx), args)
Fred Daoud
@foxdonut
Oct 18 2017 17:48
Spot on @kurtmilam , I needed the function to be delayed, and only conditionally executed.
Kurt Milam
@kurtmilam
Oct 18 2017 17:55
:+1:
Julian Coleman
@juliancoleman
Oct 18 2017 22:24
can someone help me debug a function? I have the following...
const capitalize = R.compose(
  R.join(""),
  R.juxt([R.compose(R.toUpper, R.head), R.tail]),
);

const startsWithY = R.when(
  R.equals("y", R.head),
  R.pipe(capitalize)
);

startsWithY("yes"); // => TypeError: pred is not a function
Brad Compton (he/him)
@Bradcomp
Oct 18 2017 22:27
R.equals("y", R.head) <----- This right here is asking if the function head equals the string "y"
I think you want something more like compose(equals('y'), head)
Julian Coleman
@juliancoleman
Oct 18 2017 22:27
interesting.. That's not how fp is supposed to work, however. Let me try that
Brad Compton (he/him)
@Bradcomp
Oct 18 2017 22:28
R.equals
Brad Compton (he/him)
@Bradcomp
Oct 18 2017 22:28
Given that Arrays are accessible in the same way as Objects, you could also use
R.propEq
Julian Coleman
@juliancoleman
Oct 18 2017 22:28
wrapping in compose throws First argument to _arity must be a non-negative integer no greater than ten
Lucas Schejtman
@lucasschejtman
Oct 18 2017 22:29
ramda has startsWith OOTB as well http://ramdajs.com/docs/#startsWith
Julian Coleman
@juliancoleman
Oct 18 2017 22:29
I'm not using arrays. I'm just trying to capitalize a string
derp! forgot Ramda had that
Brad Compton (he/him)
@Bradcomp
Oct 18 2017 22:30
Sry, I generally look at head as working with Arrays
Julian Coleman
@juliancoleman
Oct 18 2017 22:30
That makes perfect sense. startsWith did the trick for me
Thanks, @lucasschejtman
and thank you, @Bradcomp
Brad Compton (he/him)
@Bradcomp
Oct 18 2017 22:31
:point_up: like that?
Oh, sorry
Jonathan Chang
@jdkschang
Oct 18 2017 23:55
I noticed mergeAll doesn’t deeply merge objects. Is using mergeDeepLeft/mergeDeepRight in succession the only way to accomplish a deep merge across multiple objects ?