These are chat archives for ramda/ramda

23rd
May 2018
Rocky Madden
@rockymadden
May 23 2018 02:15
@stephenniemans :smile:
Faris Amali Alis
@f-a-a
May 23 2018 05:46

Hi all, I currently have this function:

const getAPIKey = R.pipe(
    R.path(['Items']), 
    R.head,
    R.pick(['apiKeyId', 'apiKey']),
    R.pluck('S')
  );

but flow is complaining:

Cannot call `R.pipe` because: Either function type [1] is incompatible with undefined [2] in array element. Or function type [3] is incompatible with undefined [4] in array element. Or function type [3] is incompatible with undefined [5] in array element. (References: [1] [2] [3] [4] [5])

can someone help identify whats the issue here? :/

functionalStoic
@functionalStoic
May 23 2018 11:00
@f-a-a Do you have a sample data structure?
Stephen Niemans
@stephenniemans
May 23 2018 12:49
Question for you guys. Do you prefer R.compose or R.pipe or do you use them both for different situations?
Waqas Noor
@waqasnoor
May 23 2018 12:50
i use R.compose. kind of habit. No specific reason.
Stephen Niemans
@stephenniemans
May 23 2018 12:51

I feel like compose looks more sensible on a single line, because the value is inserted on the right and flows to the left towards the variable declaration, if that makes sense.

But when it's a long multi-line sequence, pipe feels more readable top-to-bottom

Brandon Chartier
@brandonchartier
May 23 2018 12:56
I basically always use pipe, unless it's just two functions that I'm composing.
mostly from familiarity with the way compose and pipelines work in other environments
Ryan Olson
@ryanolsonx
May 23 2018 15:11
@ben-eb Thanks for the reply! I wasn't able to get that method to work. See this repl: https://goo.gl/YAx7a1
Brad Compton (he/him)
@Bradcomp
May 23 2018 15:26
I agree with @stephenniemans on this one.
Syaiful Bahri
@syaiful6
May 23 2018 15:44
@ryanolsonx try something like this o(zipObj(['name', 'type']), ap(o(pair, parseName), parseType))
Mike Lambert
@lax4mike
May 23 2018 15:45
i always use R.compose to be consistent
Ryan Olson
@ryanolsonx
May 23 2018 15:53
@syaiful6 Thanks! That seems to work for me.
Ryan Olson
@ryanolsonx
May 23 2018 16:19
Always R.compose. If things get too long, I know that it's a good time to refactor things out to other functions.
Mike Lambert
@lax4mike
May 23 2018 16:31
:point_up: good point @ryanolsonx
Waqas Noor
@waqasnoor
May 23 2018 16:54
compose is mathmetical thats why i prefer it.
Brandon Chartier
@brandonchartier
May 23 2018 17:27
ramda's compose doesn't exactly match function composition in mathematics, or other libraries/languages, due to accepting an arbitrary number of arguments, I believe - which means it can lead to things like this: ramda/ramda#1915
but I understand what you mean
Ben Briggs
@ben-eb
May 23 2018 19:16
@ryanolsonx Ahh I see. I don't think there's a good pointfree way of writing that, I think personally I would be OK with doing it the original way you were doing. I came up with this but I think it's less readable:
R.compose(
  R.evolve({
    name: parseName,
    type: parseType
  }),
  R.into({}, R.map(R.flip(R.objOf)('arg as String')))
)(['name', 'type'])
I think it can be too easy to fall into a trap of writing pointfree functions everywhere, your main goal should be readability after all :)
Ben Briggs
@ben-eb
May 23 2018 19:37
Oh, I just saw the other reply :) I think the original solution is more readable still though
Ryan Olson
@ryanolsonx
May 23 2018 19:50

@ben-eb I aim for pointfree-ness. I feel like it's usually more clean. What I ended up doing is creating a helper function:

const structure = R.curry((obj, argument) => {
  const keys = R.keys(obj)
  const fns = R.compose(R.map(key => obj[key]))(keys)

  return R.o(R.zipObj(keys), R.ap(fns))([argument])
})

Which could be called like:

const parseArgument = R.compose(structure({
  name: parseName,
  type: parseType
}, cleanArgument)

parseArgument('arg as String')
// => { name: 'arg', type: 'String' }
Ben Briggs
@ben-eb
May 23 2018 19:51
Makes sense :)
Ryan Olson
@ryanolsonx
May 23 2018 19:52
I bet that helper function could be improved but that's where I got to before checking in.
Ben Briggs
@ben-eb
May 23 2018 19:56
fns doesn't need the compose wrapper
Ryan Olson
@ryanolsonx
May 23 2018 19:57

That's something I just noticed after I pasted:

Here's my small refactor to improve it, a bit

const structure = R.curry((obj, argument) => {
  const keys = R.keys(obj)
  const objProp = R.flip(R.prop)
  const fns = R.map(objProp(obj))(keys)

  return R.o(R.zipObj(keys), R.ap(fns))([argument])
})
Ben Briggs
@ben-eb
May 23 2018 19:57
Nice :)
Ryan Olson
@ryanolsonx
May 23 2018 20:00
Thanks
Mike Lambert
@lax4mike
May 23 2018 20:22
@ram-bot
const letters = [ "a", "b", "c" ];

const letterArrays = R.zipObj(letters, R.repeat([], letters.length))

letterArrays.a.push(1);

console.log(letterArrays);
this is resulting in
{
  "a": [1],
  "b": [1],
  "c": [1]
}
uh oh!
this works:
R.over(R.lensProp("a"), R.append(1), letterArrays);
but, why are the empty arrays sharing a reference?
is there a better way to initialize this structure with empty arrays?
Brad Compton (he/him)
@Bradcomp
May 23 2018 21:09

It's unfortunately in the nature of repeat

Returns a fixed list of size n containing a specified identical value.

Instead you could use R.times(() => [], letters.length), which would generate a new array for each item in the list

Mike Lambert
@lax4mike
May 23 2018 21:09
ahh, perfect, thanks!
Brad Compton (he/him)
@Bradcomp
May 23 2018 21:10

Ahh, as I suspected, the implementation of repeat is based on times:

return times(always(value), n);

Mike Lambert
@lax4mike
May 23 2018 21:11
interesting