These are chat archives for ramda/ramda

6th
Dec 2018
Daniel Pereira
@dpereira411
Dec 06 2018 01:11
is there something like map, but where i can look into next item?
Daniel Pereira
@dpereira411
Dec 06 2018 01:16
or previous
ill try with reduce :p
Brad Compton (he/him)
@Bradcomp
Dec 06 2018 01:19
Check out aperture
Daniel Pereira
@dpereira411
Dec 06 2018 01:19
lovely :D
ramda is so awesome
Ben Briggs
@ben-eb
Dec 06 2018 09:12
Following on from last night's thought:
const W = flip(chain)(identity);

const square = W(multiply);

square(3) // 9
Alexander Lichter
@manniL
Dec 06 2018 09:37
@ben-eb Isn't that the same as unnest?
const R = require('ramda')

const W1 = R.flip(R.chain)(R.identity)
const W2 = R.unnest

const square1 = W1(R.multiply)
const square2 = W2(R.multiply)

console.log(square1(3), square2(3)) // 9, 9
Ben Briggs
@ben-eb
Dec 06 2018 09:39
@manniL Looks like it yeah! Thanks :)
Alexander Lichter
@manniL
Dec 06 2018 09:40
NP :)
Also realized this is documented like that :see_no_evil:
"Shorthand for R.chain(R.identity), which removes one level of nesting from any Chain."
Ben Briggs
@ben-eb
Dec 06 2018 09:42
@manniL So we don't really need to flip chain at all
const W = chain(identity) is also how unnest is defined
Alexander Lichter
@manniL
Dec 06 2018 09:43
@ben-eb Right! :)
Alexander Lichter
@manniL
Dec 06 2018 10:51

Imagine having a list of lists with coordinates [ [1, 2], [8, 4], ...]. I want to transform each list into an object with x and y (quite simple) but also adding a consecutive letter from the alphabet.

My approach is:

R.pipe(
  R.zipWith((letter, coords) => [letter, ...coords], alphabet), // alphabet is just a list ['a','b',...]
  R.map(R.zipObj(['letter', 'x', 'y']))
)

But I still feel it could look cleaner. Any ideas?

(Important info: I generate the coordinates from text input before, one pair per line and so on)

Full code:

 R.pipe(
  R.map(
    R.pipe(
      R.split(', '),
      R.map(Number),
    )
  ),
  R.zipWith((letter, coords) => [letter, ...coords], alphabet),
  R.map(R.zipObj(['letter', 'x', 'y']))
)
Ben Briggs
@ben-eb
Dec 06 2018 14:28
@manniL R.zipWith(R.prepend, alphabet)
Alexander Lichter
@manniL
Dec 06 2018 14:35
@ben-eb Thank you! :clap: That makes totally sense
Scott Sauyet
@CrossEye
Dec 06 2018 14:37
@mannil: Let me, guess, Advent of Code?
Alexander Lichter
@manniL
Dec 06 2018 14:38
Exactly :D
@CrossEye
Already finished both tasks but wanted to make the code cleaner :)
Scott Sauyet
@CrossEye
Dec 06 2018 14:38
Saw that problem just before I went to bed last night. Haven't tried it yet. But dreamed about how bad one of my earlier solutions was.
:smile:
Alexander Lichter
@manniL
Dec 06 2018 14:39
Oh, I don't even want to take a look on my solutions from last year :joy:
They were really messy :sweat_smile:
@CrossEye Have you solved the other tasks from the last days already? :)
Scott Sauyet
@CrossEye
Dec 06 2018 14:40
Yes, first five days.
Alexander Lichter
@manniL
Dec 06 2018 14:40
Nice! Do you have the code on GitHub?
Scott Sauyet
@CrossEye
Dec 06 2018 14:40
I haven't participated in previous years.
Alexander Lichter
@manniL
Dec 06 2018 14:40
I'd love to take a look and learn a few things :)
Scott Sauyet
@CrossEye
Dec 06 2018 14:41
In a secret gist. Some of it is too embarrassing to share at the moment. I'll try to clean it up, but perhaps these shouldn't be shared until after it's all over.
Just looking at how bad yesterday's solution was. (I really did wake up at 3AM thinking about how bad it was!)
I also started by working in plain JS, until I felt too hampered and introduced Ramda.
Alexander Lichter
@manniL
Dec 06 2018 14:43
Take your time :relaxed:
I think you can share it already. If ppl want to cheat, there are so many solution on reddit they could use.
Ah, I see! I wanted to solve all things with Ramda and "as close to the style" as possible this year
Scott Sauyet
@CrossEye
Dec 06 2018 14:44
Are there? I haven't really paid attention.
Scott Sauyet
@CrossEye
Dec 06 2018 14:46
I think I'll just stay away. :wink:
Alexander Lichter
@manniL
Dec 06 2018 14:46
I like to look at them after I solved the day, just bc I'm interested how ppl solved it in other languages
Scott Sauyet
@CrossEye
Dec 06 2018 14:47
yes, I might do that too... but I want to think about and clean mine up before that.
Alexander Lichter
@manniL
Dec 06 2018 14:47
Looking forward to it :)
Scott Sauyet
@CrossEye
Dec 06 2018 14:48
I've done problems from various places, CodeWars, Euler, etc. And I like the feature where the forum discussions open up about the solutions once you've solved them.
Alexander Lichter
@manniL
Dec 06 2018 14:49
Yeah, that's actually a nice way. But for a "public contest" it's hard to realize
Scott Sauyet
@CrossEye
Dec 06 2018 14:50
I never try to do these at midnight my time, so I'm not in the contest (at least the leaderboard one; I don't know if there's others.)
Alexander Lichter
@manniL
Dec 06 2018 14:50
Well, I'd have to wake up quite early for them, so I'm out as well :D
and I'm not into solving the puzzles quickly this year
Scott Sauyet
@CrossEye
Dec 06 2018 14:52
I've never been particularly speedy at this in any case. So I'd probably fare badly. But these puzzles are somewhat fun. I found Day 5 the easiest to code so far, but my algorithm was horribly inefficient. I'm rewriting now before I move on to Day 6.
Alexander Lichter
@manniL
Dec 06 2018 14:55
Last year I was fairly ok, but never in the leaderboards. Top 1k often though
Alexander Lichter
@manniL
Dec 06 2018 15:49
I'm looking for a more elegant way to do sth. like this (function is used in a reducer):
const willBeUsedAsReduceFunction = (shifts, [actionOne, actionTwo]) => {
  if (isShiftAction(actionOne) && !isShiftAction(actionTwo)) {
    shifts.push(actionOne)
  }
  return shifts
}
Tymoteusz Czech
@Tymek
Dec 06 2018 16:26
Hi. I'd like to ask what's expected specificity in Ramda, i.e. what belongs to the core and what should be left to other helpers. I'm asking, because I have a case where having testObject I would like to check if it contains all keys from spec object (recursive), that is: if everything from spec is equal in the same path in testObj
Ben Briggs
@ben-eb
Dec 06 2018 17:02
@manniL Check out R.both
Oh, wait. Maybe not because you have two different variables to inspect
Alexander Lichter
@manniL
Dec 06 2018 17:03
@ben-eb yes, unfortunately :see_no_evil:
Ben Briggs
@ben-eb
Dec 06 2018 17:04
I'm wondering if there's a pointfree way of expressing this:
const x = {
  fn: always(42)
};

evolve({
  fn: o => compose(inc, o)
})(x).fn() // 43
It's not really necessary for it to be pointfree I'm wondering if it's possible :)
Alexander Lichter
@manniL
Dec 06 2018 17:13
it's possible I think
Ben Briggs
@ben-eb
Dec 06 2018 17:13
@Tymek Did you try whereEq ?
whereEq({
  a: {
    b: 'c'
  }
})({
  a: {
    b: 'c'
  }
}) // true
Alexander Lichter
@manniL
Dec 06 2018 17:14
@ben-eb So close :see_no_evil:
const res = evolve({
  fn: compose(inc, call)
})(x).fn //43
But you can't call the fn ^^#
Ben Briggs
@ben-eb
Dec 06 2018 17:14
Yeah, that's the gotcha :) We want to delay evaluation
Alexander Lichter
@manniL
Dec 06 2018 17:15
const res = evolve({
  fn: compose(always, inc, call)
})(x).fn()
Like that? :D
Ben Briggs
@ben-eb
Dec 06 2018 17:15
Nice, thanks! :+1:
Alexander Lichter
@manniL
Dec 06 2018 17:16
You are welcome :)
Tymoteusz Czech
@Tymek
Dec 06 2018 17:16
@ben-eb o. thx! Somehow I missed it.
Ben Briggs
@ben-eb
Dec 06 2018 17:19
@manniL Ahhh it's not quite the same
@manniL If we then call the func with some args then it falls over
Alexander Lichter
@manniL
Dec 06 2018 17:20
@ben-eb Dang! :see_no_evil:
In which case(s)?
Ben Briggs
@ben-eb
Dec 06 2018 17:20
@manniL Yeah the idea is to take some existing object method, apply the original method with its args and then run our function afterwards

@manniL

const x = {
  fn: multiply(2)
};

evolve({
  fn: o => compose(inc, o)
})(x).fn(2)

Should be 5

Johnny Hauser
@m59peacemaker
Dec 06 2018 17:22
@CrossEye thanks
Ben Briggs
@ben-eb
Dec 06 2018 17:22
@Tymek You're welcome :)
Johnny Hauser
@m59peacemaker
Dec 06 2018 17:24
Since the hareactive chat has no activity.... does anyone here know much about it - more importantly the theory behind it, or perhaps even better, the Conal Elliot concept of FRP, i.e. reactive-banana?
There is a lot that I like about "Classic FRP", if that's the right way to describe it, but I can't figure out how they are composing "time".
In a lot of JS observable libraries, there is zip, which is somewhat of a barrier https://en.wikipedia.org/wiki/Barrier_(computer_science)
It's like lifting the values of the observables, but associating them with a barrier of their times
Zip is like this to me:
const time = barrier([ a, b, c ])
const value = lift (sum) ([ a, b, c ])
const zipped = when (time) (value)
Johnny Hauser
@m59peacemaker
Dec 06 2018 17:29
But I can't imagine how to implement such a thing, nor understand or find anything about how the classic frp folks are doing that.
Ben Briggs
@ben-eb
Dec 06 2018 17:36
@manniL I worked it out. It's just map(inc)
@manniL Alternately you could use B combinator; const B = f => g => x => f(g(x)); - which is the same thing
@manniL I guess the only problem is that it's still not as good as the original implementation because it now has to be a unary function (whereas the other preserved arity)
Ben Briggs
@ben-eb
Dec 06 2018 18:23
For completeness' sake:
const x = {
  fn: multiply(2)
};

evolve({
  fn: map(inc)
})(x).fn(2) // 5
Kurt Milam
@kurtmilam
Dec 06 2018 18:31
@ben-eb I think o(inc) will also work if you want to save a couple of keystrokes :D
It works for your example - not sure whether it fails on any others.
Brad Compton (he/him)
@Bradcomp
Dec 06 2018 18:31
With the added bonus of your code sounding like a pig
Kurt Milam
@kurtmilam
Dec 06 2018 18:32
:thumbsup:
The oink combinator.
Brad Compton (he/him)
@Bradcomp
Dec 06 2018 18:32
hahaha
Ben Briggs
@ben-eb
Dec 06 2018 18:32
:joy:
Why does o work and compose doesn't?
Brad Compton (he/him)
@Bradcomp
Dec 06 2018 18:33
:tophat: :sparkles: Magic
Because compose is variadic, while o is binary and will wait for that second argument
So compose with a single argument will return an uncurried version of the function you passed in, while o will return a function that's witing for the second half of the composition
Ben Briggs
@ben-eb
Dec 06 2018 18:35
Ahhh, thanks :) Still it means in this case that x => compose(inc, x) is better if we assume x is not a unary function, but o(inc) is better if it is
Kurt Milam
@kurtmilam
Dec 06 2018 18:39
if pigs could fly (sorry, delayed combinator joke)
Ben Briggs
@ben-eb
Dec 06 2018 18:51
@manniL I'm not sure if it's better (it's probably not as easy to grok) but I had a go at your earlier question:
const isShiftAction = propEq('shift', true);
const isNotShiftAction = complement(isShiftAction);

const appendTo = flip(append)

const willBeUsedAsReduceFunction = shifts =>
  ifElse(
    both(
      compose(isShiftAction, head),
      compose(isNotShiftAction, last)
    ),
    compose(appendTo(shifts), head),
    always(shifts)
  )

willBeUsedAsReduceFunction([])([{ shift: true }, {}])
Now we're not mutating shifts :)
Scott Sauyet
@CrossEye
Dec 06 2018 19:08
Note that o is technically ternary: (b → c) → (a → b) → a → c. That is
o(f, g, x) //=> f(g(x))
Brad Compton (he/him)
@Bradcomp
Dec 06 2018 19:09
good point
Scott Sauyet
@CrossEye
Dec 06 2018 19:10
But I don't think I've ever called it that way. It's always either o(f)(g)(x) or o(f, g)(x).