These are chat archives for ramda/ramda

11th
Apr 2017
Gents! R.zip function can only zip 2 lists.
I have a usecase where it makes sense to zip multiple series together.
So I did an example to zip it for 4 lists.
I think it can be generalized quite easily.
Is this a good idea?
Or is this against Ramda philosophy?
Denis Stoyanov
@xgrommx
Apr 11 2017 08:53
@awb99 in haskell exists zipWithN but sometime I hate it, we can use second part of applicative of lists like a ZipList in js I have this one solution https://github.com/xgrommx/practical-functional-programming/blob/master/zip-list.js#L62 just applicative sequence of lists
awb99
@awb99
Apr 11 2017 09:13
@xgrommx Thanks! You have a complex library :+1:
Denis Stoyanov
@xgrommx
Apr 11 2017 09:14
@awb99 this repo was just for fun :smile:
Kurt Milam
@kurtmilam
Apr 11 2017 09:55
Is there a way to get from 'test' to 'Test' without an explicit join?
compose( join( '' )
       , over( lensIndex( 0 ), toUpper )
       )( 'test' ) // -> 'Test'
Stephan Meijer
@smeijer
Apr 11 2017 11:00
I think not, because it's just how JS works. You must take the first letter separately to be able to do the correct string manipulations. You could not use join, but than it's simply replaced by a concat. Missing the point a bit I guess:
const char0 = lens(head, useWith(concat, [identity, tail]));
const capitalize = over(char0, toUpper);
capitalize('test') // -> 'Test';
Kurt Milam
@kurtmilam
Apr 11 2017 11:04
@smeijer thanks, I figured that was the case, but thought I'd check to be sure.
Iain Freestone
@iainfreestone
Apr 11 2017 11:11
@kurtmilam could you use something like replace(/([a-z])/,toUpper)('test')
Stephan Meijer
@smeijer
Apr 11 2017 11:13
regex for capitalization :worried: , also failing on: ‍édward‍‌ => ⁠éDward‌⁠
Iain Freestone
@iainfreestone
Apr 11 2017 11:14
fair enough
László Vadász
@maxinteger
Apr 11 2017 11:31
replace(/^(.)/,toUpper)('édward‍‌')
Stephan Meijer
@smeijer
Apr 11 2017 12:35
R.contains({ name: 'Fred' }, [{ name: 'Fred', age: 12 }]);
Any way to fix this? Contains matches the whole object, where I simply want to see if any object matches the keys of my object.
Like lodash:
_.some([{ name: 'Fred', age: 12 }], { name: 'Fred' });
Kurt Milam
@kurtmilam
Apr 11 2017 12:36
What do you want to return?
Stephan Meijer
@smeijer
Apr 11 2017 12:36
the matched objects
I currently have:
const list = {
  tasks: [
    { id: 2, state: 'todo', users: [{ id: 1 }] },
    { id: 2, state: 'todo', users: [{ id: 1 }, { id: 5 }] },
    { id: 4, state: 'todo', users: [{ id: 2 }] },
  ],
};

const tasksForUser = id => R.compose(
  R.defaultTo([]),
  R.filter(R.where({ users: R.contains({ id }) })),
);
Kurt Milam
@kurtmilam
Apr 11 2017 12:37
filter+propEq might do the trick.
ok, that looks a little different than your example. gimme a sec.
Stephan Meijer
@smeijer
Apr 11 2017 12:41
this fails as soon as a taskstart to look like: { id: 2, state: 'todo', users: [{ __type: 'User', id: 1, name: 'John' }] },
Stephan Meijer
@smeijer
Apr 11 2017 12:49
// native js version
const tasksForUser = id => list => list.tasks.filter(t => t.users.some(u => u.id === id)); 
const tasks = tasksForUser(5)(list);
Kurt Milam
@kurtmilam
Apr 11 2017 12:54
@smeijer This does the trick, but I'm sure it could be tidied up some.
const tasksForUser = _id => R.compose(
  R.defaultTo( [] ),
  R.filter( R.compose( R.contains( { id: _id } ), R.prop( 'users' ) ) ),
  prop( 'tasks' )
)
Stephan Meijer
@smeijer
Apr 11 2017 13:00

Thats basically the same as I had. The problem is that contains does a full match, and not a partial:

https://goo.gl/sj2ihP

Thats why my initial example was more simple. I need a partial matcher
I guess I should have answered your "what do you want to return" question with "a boolean" :blush: , as it is the inner part of the where clause.
Kurt Milam
@kurtmilam
Apr 11 2017 13:16
I think that does the trick.
const tasksForUser = _id =>
  compose( filter( compose( any( propEq( 'id', _id ) )
                          , prop( 'users') 
                          ) 
                 )
         , prop( 'tasks' )
         )
But I wouldn't be surprised to find that there's a more concise way to do it.
Stephan Meijer
@smeijer
Apr 11 2017 13:44
The more I play with Ramda, the more I'm feeling for native js (es6) methods.
Stephan Meijer
@smeijer
Apr 11 2017 14:20
@kurtmilam I ended up with:
const hasUser = R.useWith(R.any, [R.whereEq, R.propOr([], 'users')]);

const filterByUser = R.useWith(
  R.filter, [hasUser, R.pathOr([], ['tasks'])],
);

filterByUser({ id: 2 })(list);
Kurt Milam
@kurtmilam
Apr 11 2017 14:22
:thumbsup: I think lenses are nice for this kind of thing.
Stephan Meijer
@smeijer
Apr 11 2017 14:23
yes, I'm sure they come in handy here. But I cannot wrap my head around them. Ramda is really difficult when compared to native or lodash :(
Kurt Milam
@kurtmilam
Apr 11 2017 14:24
Restate: I think ES6 arrow functions can nicely fill in for a lot of what ramda does. I don't find ramda difficult in comparison to lodash, however.
Take a look at partial.lenses if you're interested.
Michael Rosata
@mrosata
Apr 11 2017 14:28
@kurtmilam I agree, lenses are great for nested values. @smeijer Ramda can be tricky at first, functional programming in general is a strange concept to learn. The important thing to remember is that Ramda (like functional programming), doesn't have to be an all or nothing pursuit. Oftentimes I'll find myself trying to find a solution with Ramda when a plain ES6 solution would work much better. So if your finding Ramda code difficult to read it might be helpful to scale back Ramda and use more ES6 until you adjust and find your perfect balance of the two
Bravi
@Bravilogy
Apr 11 2017 15:37

Hi guys. I have an array of numbers like

const numbers = [1, 2, 3, 4, 5];

and I'd like to generate a combination of 2 numbers like:

const combos = [[1, 2], [1, 3], [1, 4], [1, 5], ...
is there a function I can use for this?
Kurt Milam
@kurtmilam
Apr 11 2017 15:37
Denis Stoyanov
@xgrommx
Apr 11 2017 15:40
@Bravilogy converge(lift((a, b) => [a, b]), [take(1), tail])([1, 2, 3, 4, 5])
@Bravilogy or converge(liftN(2, unapply(identity)), [take(1), tail])([1, 2, 3, 4, 5])
Mick Dekkers
@mickdekkers
Apr 11 2017 15:42
Is this the right place to ask questions about ramda-fantasy? I'm trying to understand how to compose Readers but I haven't been able to find much info about it (that I could understand; I'm fairly new to this part of fp).
This is what I've got so far: https://runkit.com/soullesswaffle/58ecf200e5b718001401453d
Bravi
@Bravilogy
Apr 11 2017 15:54
@xgrommx oh thanks
I'll have a look now
Rick Medina
@rickmed
Apr 11 2017 15:55
@SoullessWaffle did you checkout the example in the repo?
Kurt Milam
@kurtmilam
Apr 11 2017 15:57
@smeijer Here's an improved lens-based solution from the main developer of partial.lenses:
const tasksForUser = id =>
  [ 'tasks'
  , L.elems
  , L.when( L.any( R.equals( id ), [ 'users', L.elems, 'id' ] ) )
  ]

L.collect( tasksForUser( 1 ), list )
The cool thing about this is that tasksForUser( id ) is also writeable.
Galileo Sanchez
@galileopy
Apr 11 2017 15:58
@SoullessWaffle if I understand correctly you want to have a point free version of the following?
const fnA = (a) => Reader(env => a + env.a)
const fnB = (b) => Reader(env => b + env.b)
const fnAB = fnA(20).chain(fnB)
Mick Dekkers
@mickdekkers
Apr 11 2017 16:21
I did but I don't fully understand what's going on there
@galileopy pointfree would be a nice bonus yeah
Galileo Sanchez
@galileopy
Apr 11 2017 16:27
got an answer to your question on the fantasy-land channel @SoullessWaffle pipeK(fnA, fnB), credits to @gabejohnson
Rick Medina
@rickmed
Apr 11 2017 16:27
@SoullessWaffle checkout the example and video links
Gabe Johnson
@gabejohnson
Apr 11 2017 16:45
@galileopy @SoullessWaffle I was curious so I tried it out
const Reader = require('ramda-fantasy').Reader;
const R = require('ramda');

const fnA = (a) => Reader(env => a + env.a)
const fnB = (b) => Reader(env => b + env.b)

const fnAB = R.pipeK(fnA, fnB);

Reader.of(20).chain(fnAB).run({ a: 1, b: 2})
It works
Galileo Sanchez
@galileopy
Apr 11 2017 16:48
@gabejohnson thanks a lot, I think one can simply do fnAB(20) as I did, since fnA takes a number and returns a reader, at least that's how I tried it.
Gabe Johnson
@gabejohnson
Apr 11 2017 16:51
@galileopy cool. I've never used the (Reader, Writer, IO, State) monads before
Rick Medina
@rickmed
Apr 11 2017 16:51
:+1: , a previous version R.pipeK expected an unlifted value as in Gabe's version
a lifted *
Galileo Sanchez
@galileopy
Apr 11 2017 16:52
:)
Mick Dekkers
@mickdekkers
Apr 11 2017 18:01
@galileopy @rickmed @gabejohnson thanks everyone! Looks like I have some reading up to do :D
Is there a difference between Reader() and Reader.ask.map()? They both seem to work with pipeK: https://runkit.com/soullesswaffle/58ed1999e5b718001401569c
Gabe Johnson
@gabejohnson
Apr 11 2017 18:07
@SoullessWaffle both of those return an instance of the Reader monad. So they can be used in the same way.
Mick Dekkers
@mickdekkers
Apr 11 2017 18:09
Ah alright, thanks for clearing that up :)