These are chat archives for ramda/ramda

11th
Apr 2016
David Langford
@That-David-Guy
Apr 11 2016 01:25
Hi all, loving the library. Is there anyway I can make the following nicer
// [{a:[1,2], b:[3,4]}, {a:[2,22], b:[99,100]}] => 99 (max value from the 'a' prop arrays)
This is what I have
import { compose, curry, flatten, reduce, max, map, prop } from 'ramda'

// [1, 2, 34, 4, 5] => 34
const findMax = reduce(max, 0)

// ( 'a', [{a: [1,2,3], b: 'hello'},{a: [4,5,6], b: 'world'}] ) => [ [1,2,3], [4,5,6] ]
const mapProp = curry( (key, list) =>  map(prop(key), list) )


// ( 'a', [{a:[1,2], b:[3,4]}, {a:[2,22], b:[99,100]}] ) => [ 1, 2, 22 ]
const flattenObjectsToPropValues = curry( (key, list) => compose(flatten, mapProp(key))(list) )

module.exports = {
  getMaxHistoricalPriceFromOffers: compose(findMax, flattenObjectsToPropValues('a'))
}
looks for how to use gitter markup
Hardy Jones
@joneshf
Apr 11 2016 01:26
you need a line feed after the triple backticks
you can edit it
SHIFT+ENTER to enter a line-feed
David Langford
@That-David-Guy
Apr 11 2016 01:28
Thanks!
So I have a list of objects, which have a prop is an array of numbers. I want the max number from the arrays from all of the objects. Is there a cleaner way to do it?
Hardy Jones
@joneshf
Apr 11 2016 01:31
mapProp == R.pluck
R.pluck
David Langford
@That-David-Guy
Apr 11 2016 01:32
Thanks! I've been looking for something like that for a while. I must have missed it
Hardy Jones
@joneshf
Apr 11 2016 01:36
hmm.
maybe maxBy?
Hardy Jones
@joneshf
Apr 11 2016 01:43
maybe not
David Langford
@That-David-Guy
Apr 11 2016 01:43
var data = [{a: [1,2,3], b: 'hello'},{a: [4,5,6], b: 'world'}]

// [1,2,3,4,5,6]
var flatData = R.flatten(R.pluck('a', data))

R.maxBy(R.identify, 0, flatData) // GET ERROR, f is not a function
R.reduce(R.maxBy(R.identity), 0, flatData);
seems to work
Hardy Jones
@joneshf
Apr 11 2016 01:46
yeah, I was thinking something else though, but I don't think it'll work.
I dunno, what you wrong is probably fine with max.
David Langford
@That-David-Guy
Apr 11 2016 01:46
R.reduce(R.max,0,flatData)
So I was pretty close. I just created my own pluck when I could have used ramdas.

It went from

import { compose, curry, flatten, reduce, max, map, prop } from 'ramda'

// [1, 2, 34, 4, 5] => 34
const findMax = reduce(max, 0)

// ( 'a', [{a: [1,2,3], b: 'hello'},{a: [4,5,6], b: 'world'}] ) => [ [1,2,3], [4,5,6] ]
const mapProp = curry( (key, list) =>  map(prop(key), list) )


// ( 'a', [{a:[1,2], b:[3,4]}, {a:[2,22], b:[99,100]}] ) => [ 1, 2, 22 ]
const flattenObjectsToPropValues = curry( (key, list) => compose(flatten, mapProp(key))(list) )

module.exports = {
  getMaxHistoricalPriceFromOffers: compose(findMax, flattenObjectsToPropValues('a'))
}

to

import { compose, curry, flatten, pluck, reduce, max, } from 'ramda'

// [1, 2, 34, 4, 5] => 34
const findMax = reduce(max, 0)

// ( 'a', [{a:[1,2], b:[3,4]}, {a:[2,22], b:[99,100]}] ) => [ 1, 2, 22 ]
const flattenObjectsToPropValues = curry( (key, list) => compose(flatten, pluck(key))(list) )

module.exports = {
  getMaxHistoricalPriceFromOffers: compose(findMax, flattenObjectsToPropValues('a'))
}

Saved myself a line :)

Thanks for the help!
Hardy Jones
@joneshf
Apr 11 2016 01:58
Stylistically, you might want to drop the compose in flattenObjectsToPropValues.
Seems a bit unnecessary.
David Langford
@That-David-Guy
Apr 11 2016 01:59
And have it as flatten(pluck(key))?
Hardy Jones
@joneshf
Apr 11 2016 01:59
flatten(pluck(key, list))
David Langford
@That-David-Guy
Apr 11 2016 02:00
ahh yep
Hardy Jones
@joneshf
Apr 11 2016 02:01
Also, It's kind of weird that there's no maximum of an array
in ramda
David Langford
@That-David-Guy
Apr 11 2016 02:01
Playing around more, I think I can just do this
import { compose, flatten, pluck, reduce, max } from 'ramda'

// [1, 2, 34, 4, 5] => 34
const findMax = reduce(max, 0)

module.exports = {
  getMaxHistoricalPriceFromOffers: compose(findMax, flatten, pluck('a'))
}
Hardy Jones
@joneshf
Apr 11 2016 02:01
even better
David Langford
@That-David-Guy
Apr 11 2016 02:02
Such a good feeling when you remove lines
Hardy Jones
@joneshf
Apr 11 2016 02:02
:)
David Langford
@That-David-Guy
Apr 11 2016 02:03
Thanks again for all the help
Hardy Jones
@joneshf
Apr 11 2016 02:12
:+1:
Stepan Kuzmin
@stepankuzmin
Apr 11 2016 07:22
Hi there! Is there any deep merge in Ramda?
Aldwin Vlasblom
@Avaq
Apr 11 2016 13:22
@ram-bot R.merge({obj: {deep: false}}, {obj: {deep: true}})
ram-bot
@ram-bot
Apr 11 2016 13:22
{ obj: { deep: true } }
Aldwin Vlasblom
@Avaq
Apr 11 2016 13:22
@stepankuzmin ^
Stepan Kuzmin
@stepankuzmin
Apr 11 2016 13:25
Hmm, thanks for reply @Avaq! But then I try something like
@ram-bot R.merge({a: {b: {c: {d: 1, e: 2}}}}, {a: {b: {c: {f: 3, g: 3}}}})
ram-bot
@ram-bot
Apr 11 2016 13:25
{ a: { b: { c: [Object] } } }
Stepan Kuzmin
@stepankuzmin
Apr 11 2016 13:26
I’m getting {"a": {"b": {"c": {"f": 3, "g": 3}}}}
Instead of {"a": {"b": {"c": {"d": 1, "e": 2, "f": 3, "g": 3}}}}
Raine Virta
@raine
Apr 11 2016 13:29
@ram-bot R.merge({a: {b: {c: {d: 1, e: 2}}}}, {a: {b: {c: {f: 3, g: 3}}}})
ram-bot
@ram-bot
Apr 11 2016 13:29
{ a: { b: { c: { f: 3, g: 3 } } } }
Raine Virta
@raine
Apr 11 2016 13:29
fixed that
Aldwin Vlasblom
@Avaq
Apr 11 2016 13:30
Ah, yes. My example does not properly show whether it goes deep or not. Whoops.
Erki Esken
@erkiesken
Apr 11 2016 13:48
there’s no such deep merge in ramda. there are many discussions in ramda github issues about why not. for your case if you know certain deep path needs special merging then evolve might work, ie:
> one = {a: {b: {c: {d: 1, e: 2}}}}
> two = {a: {b: {c: {f: 3, g: 3}}}}
> console.log("%j", R.evolve({ a: { b: { c: R.merge(one.a.b.c) } } } , R.merge(one, two)))
{"a":{"b":{"c":{"d":1,"e":2,"f":3,"g":3}}}}
Aldwin Vlasblom
@Avaq
Apr 11 2016 14:09
You can also do mergeWith(mergeWith(mergeWith(merge))), which would deep-merge objects up to 4 levels deep. ^^
Denys Mikhalenko
@prontiol
Apr 11 2016 14:19
haha
Julien Goux
@jgoux
Apr 11 2016 15:01
is there a function to extract values from a string/list between two indexes ?
Erki Esken
@erkiesken
Apr 11 2016 15:02
R.slice
Julien Goux
@jgoux
Apr 11 2016 15:02
obviously ! ^^
Thank you !!!
Dalibor Novak
@BorePlusPlus
Apr 11 2016 15:12
Is there a particularly elegant way of splitting list into two halves?
David Chambers
@davidchambers
Apr 11 2016 15:13
R.splitAt
Dalibor Novak
@BorePlusPlus
Apr 11 2016 15:13
Cheers :+1: - was just eyeing it myself :smile:
Dalibor Novak
@BorePlusPlus
Apr 11 2016 15:19
It turned out to be a bit of a mouthful
var splitInHalf = R.converge(R.splitAt, [R.pipe(R.length, R.divide(R.__, 2)), R.identity])
could it be done prettier, or is that about it?
Irakli Safareli
@safareli
Apr 11 2016 15:40
R.dissoc(90, {a: 1, 90: 2})
returns {a: 1, 90: 2}
Dalibor Novak
@BorePlusPlus
Apr 11 2016 15:41
It takes string as first param according to documentation
R.dissoc
Dalibor Novak
@BorePlusPlus
Apr 11 2016 15:43
I guess the behaviour is undefined for other cases. More knowledgeable people can fill in...
Erki Esken
@erkiesken
Apr 11 2016 15:44
looking how it’s implemented it make sense that 90 does not match in the for loop:
https://github.com/ramda/ramda/blob/v0.20.1/src/dissoc.js
> o = { a: 1, 90: 2 }
{ '90': 2, a: 1 }
> for (i in o) { console.log(i, typeof i) }
90 string
a string
Irakli Safareli
@safareli
Apr 11 2016 15:45
yes but i's kinda not that intuitive
so i have to map on all keys to strings to call dissocPath
like R.dissocPath([somekey, someid].map(String))
Lewis
@6ewis
Apr 11 2016 17:07
hello
http://goo.gl/i1l36A what's better. Set or uniq
Dalibor Novak
@BorePlusPlus
Apr 11 2016 17:16

In the case that you used - I prefer uniq as it makes it clearer that you want a List with uniq members (to which you might later add duplicates)

Excuse me for stating the obvious, but I would use Set if I needed a (go figure) Set

But this is just my opinion.
Lewis
@6ewis
Apr 11 2016 17:24
I see
@BorePlusPlus when would you use R.map over map
Dalibor Novak
@BorePlusPlus
Apr 11 2016 17:25
When I'd want to compose it, or just bind a single parameter etc.
I am sure the FP posse can give better answer than than though.
benefits are that it is a function not a method and that it is curried
also it has the params in "the right order" - see 'Hey Underscore, You're Doing It Wrong' video
Lewis
@6ewis
Apr 11 2016 17:29
wouldn't be nice if map() had a continue;break like the for loop
@BorePlusPlus I see
Brad Compton (he/him)
@Bradcomp
Apr 11 2016 17:32
I use R.map most of the time, but I'll occasionally use .map() if it makes sense in the context. If I am doing a composition, or if I am partially applying the function, or if I am mapping over something that isn't a native array, or if it's more readable in the context of what I'm doing, I use R.map.
Chet Harrison
@ChetHarrison
Apr 11 2016 17:34
Is there a way to search the docs by the HM signature?
David Chambers
@davidchambers
Apr 11 2016 17:35
Not currently.
Brad Compton (he/him)
@Bradcomp
Apr 11 2016 17:35
@ChetHarrison I wish!
Chet Harrison
@ChetHarrison
Apr 11 2016 17:36
yeah. that would be super slick. Prob eliminate half the questions in this room
Scott Sauyet
@CrossEye
Apr 11 2016 17:38
@ChetHarrison: if you have any idea on how to make that work, I'm all ears!
Chet Harrison
@ChetHarrison
Apr 11 2016 17:39
ha. Yeah there will be issues of what char did you use to represent your generic types
I'd prob start by looking at how they did it @CrossEye https://www.haskell.org/hoogle/
Lewis
@6ewis
Apr 11 2016 17:51
@Bradcomp I see thanks
do we have Array#find, R#find seems to be reserved for arrays of objects
Brad Compton (he/him)
@Bradcomp
Apr 11 2016 17:53
@ram-bot
R.find(a => a === 1, [5,6,7,3,1]);
ram-bot
@ram-bot
Apr 11 2016 17:53
1
Brad Compton (he/him)
@Bradcomp
Apr 11 2016 17:54
You could also use R.equals to do the same thing
Lewis
@6ewis
Apr 11 2016 17:54
i see thanks
Lewis
@6ewis
Apr 11 2016 18:01
what am I doing wrong
One thing against ramda is that it's not easy to debug
Brad Compton (he/him)
@Bradcomp
Apr 11 2016 18:05
@6ewis I agree. Also, taking a look
Dalibor Novak
@BorePlusPlus
Apr 11 2016 18:08
I find that a logfunction can go a long way when debugging
Chet Harrison
@ChetHarrison
Apr 11 2016 18:08
tap = x => {
        console.log( x );
        return x;
    },
Dalibor Novak
@BorePlusPlus
Apr 11 2016 18:09
That. Was just trying to type it on phone...
Brad Compton (he/him)
@Bradcomp
Apr 11 2016 18:10
@BorePlusPlus There's R.tap
Lewis
@6ewis
Apr 11 2016 18:10
@Bradcomp i updated it just in case http://goo.gl/M1eYSB
Chet Harrison
@ChetHarrison
Apr 11 2016 18:10
It's a bit like writing with your non dominant hand at first but once you start thinking in composition you can radically decompose your logic into very testable chunks
Dalibor Novak
@BorePlusPlus
Apr 11 2016 18:11
@Bradcomp nice :+1:
Brad Compton (he/him)
@Bradcomp
Apr 11 2016 18:11
@6ewis Can you describe a little what you are trying to do? I'm having a little trouble following the code.
Dalibor Novak
@BorePlusPlus
Apr 11 2016 18:12
Laters folks
Lewis
@6ewis
Apr 11 2016 18:17
@Bradcomp http://goo.gl/sCdQch, the first piece of code commented out is what I'm trying to do
@BorePlusPlus later
Brad Compton (he/him)
@Bradcomp
Apr 11 2016 18:20
@6ewis So attributeName would be 'name'
Lewis
@6ewis
Apr 11 2016 18:21
@Bradcomp yes. sorry
Brad Compton (he/him)
@Bradcomp
Apr 11 2016 18:24
So for each unique name, you need an element object based on that name which includes the original index in the key field (among other things)?
Lewis
@6ewis
Apr 11 2016 18:25
@Bradcomp yes sir
Brad Compton (he/him)
@Bradcomp
Apr 11 2016 18:27
If a name occurs more than once, does it matter if you use the first or second occurrence?
Here is what happens when I just fixed the two issues that were causing it not to run: http://goo.gl/AJulxE
Sorry I forgot to tag you @6ewis
Brad Compton (he/him)
@Bradcomp
Apr 11 2016 18:35
@6ewis Here I added addIndex to the R.when call to preserve the index
@6ewis There is still the issue of uniqueness, which isn't being preserved
Lewis
@6ewis
Apr 11 2016 18:41
@Bradcomp what was the issue on 1st link
Brad Compton (he/him)
@Bradcomp
Apr 11 2016 18:44
@6ewis I added the keyword let before content, then wrapped R.map by itself in addIndex, instead of wrapping the entire expression in addIndex
@6ewis Gimme a few and I'll get you something a little clearer
Lewis
@6ewis
Apr 11 2016 18:48
@Bradcomp you're right findKey, which should actually be named doesNotFindKey is useless here it does not solve the problem of uniqueness like the plain js
Erki Esken
@erkiesken
Apr 11 2016 18:48

One thing against ramda is that it's not easy to debug

i’ve found treis (https://github.com/raine/treis) module to be very helpful. use like so:

R.compose(
   treis(“mapping foo”, R.map(foo)),
   treis(“plucking bar”, R.pluck(“bar”)),
   treis(“some other fn call", someFn)
)(data)

and it will give you nice named logging lines with input and output at every step.

Lewis
@6ewis
Apr 11 2016 18:49
@Bradcomp what's the difference between wrapping addIndex around r/map by itself and wrapping it around R.map and its arguments
Brad Compton (he/him)
@Bradcomp
Apr 11 2016 18:57

@6ewis addIndex takes a single parameter, which is expected to be a function (let's call it f). f is a function that is expected to have, as it's first parameter, another function (g). addIndex will add an index parameter to function g.

So in the case of map, if we want to add the index parameter to the mapping function, we pass it in by itself, and then use the modified map to process our list.

R.addIndex(R.map)(createElementIFFkeyNotPresentInArrayOfNames,content)

In the case of when, we want the index added to the second function we pass in, so we need to pass the function into addIndex with the first argument (the check) already applied.

R.addIndex(R.when(findKey))(createElementWithNewProps);
^^^That way, addIndex adds the index parameter to createElementWithNewProps
Lewis
@6ewis
Apr 11 2016 19:01
I see. thanks for the clear explanation
Brad Compton (he/him)
@Bradcomp
Apr 11 2016 19:07
@6ewis Here is an alternative. It preserves the first instance of each name in the final list, and is hopefully a little clearer to read.
http://goo.gl/HN3ycM
@6ewis I created two identical copies of the object in content, just so we could ensure uniqueness was occurring.
Lewis
@6ewis
Apr 11 2016 19:18
@Bradcomp oh i see. I'll have a look now thanks. I was going a different route http://goo.gl/OPcQkI
Lewis
@6ewis
Apr 11 2016 19:24
@Bradcomp well i shouldn't have used anyPass, ignore my bad solution :/
@Bradcomp thanks. it was so much harder to write than plain js with sideeffect
Brad Compton (he/him)
@Bradcomp
Apr 11 2016 19:40

@6ewis I think it's a matter of what we're used to. I like the functional version because it's more declarative. Once you get used to it, all you need to think about is what transformations need to be made on the data. After doing it for a while, it becomes a lot more natural to identify the functional patterns in what you are trying to do, and just apply them.

I think the functional versions are easier to read when you come back to your code down the line, but that may be personal bias. It helps to really break things down into atomic actions / transformations, and then see how those can be put together.

Lewis
@6ewis
Apr 11 2016 19:45
@Bradcomp i agree that it's easier to read down the line, that is if you get used to the the functional style
R.pluck('a')([{a: {b: 1}}, {a: 2}])
will get me a's, what if i need b
Brad Compton (he/him)
@Bradcomp
Apr 11 2016 19:47
@ram-bot
let arr = [{a: {b: 1}}, {a: 2}]
R.map(R.path(['a', 'b']))(arr)
ram-bot
@ram-bot
Apr 11 2016 19:47
SyntaxError: Block-scoped declarations (let, const, function, class) not yet supported outside strict mode
Brad Compton (he/him)
@Bradcomp
Apr 11 2016 19:47
@ram-bot
var arr = [{a: {b: 1}}, {a: 2}]
R.map(R.path(['a', 'b']))(arr)
ram-bot
@ram-bot
Apr 11 2016 19:47
[ 1, undefined ]
Lewis
@6ewis
Apr 11 2016 19:50
@ram-bot
var arr = [{a: {b: 1}}, {a: 2}]
R.map(R.path(['a', 'b']), arr))
Raine Virta
@raine
Apr 11 2016 19:55
rambot doesn't pick up on edits
Chet Harrison
@ChetHarrison
Apr 11 2016 20:06
@CrossEye I was thinking about the search by HM signature. Prob the easiest way would be to include those strings in the list of items searched. IE "(a, b)" would match Reduce ((a, b) → a) → a → [b] → a
Brad Compton (he/him)
@Bradcomp
Apr 11 2016 20:44
@ChetHarrison @CrossEye I would be fine with the ability to click on a signature and have it show all the functions with the same signature, similar to how the Function List Logic etc. filtering works now.
LeonineKing1199
@LeonineKing1199
Apr 11 2016 21:56
:+1:
Chet Harrison
@ChetHarrison
Apr 11 2016 21:56
@Bradcomp presumably if to functions share the same signature they would be doing the same thing, therefor aliases of each other. I do like the select by type catagory. For a specific example check this out https://www.haskell.org/hoogle/?hoogle=%28a+-%3E+b%29+-%3E+%5Ba%5D+-%3E+%5Bb%5D
LeonineKing1199
@LeonineKing1199
Apr 11 2016 21:56
That's certainly not a valid assumption
Literally, add(a, b), subtract(a, b)
Both can take numeric types but do different things
Chet Harrison
@ChetHarrison
Apr 11 2016 21:57
I stand corrected