These are chat archives for ramda/ramda

23rd
Apr 2015
Eugene Lerman
@airbugg
Apr 23 2015 16:19
hi guys! i'm struggling with a little piece of code and was wondering if you could point out the obvious bit i'm missing (:
suppose i have an array of arrays with this form: [ ['string1', 'string2', 'string3'], ... , ['string2', 'string2', 'stringN'] ]. I'm trying to return an object of this form: { 'string1' : # of occurrences at index 0, ..., 'stringN': # of occurrences at index 0}. Basically, i have an array of array of fixed length (3 in my example). I would like to extract a count of all strings at a specific position in each array (in my example, i'd like to get a breakdown of strings and the number of times they appear at index 1 in every array). this is my code:
var atIndex = R.curry( function (index, arr) { return arr[index]; }); 
var concactByIndex = R.chain(atIndex, R.__);
var countOccurrences = R.countBy(R.identity, concactByIndex);
However, when i try to call countOccurences(1, collection) I get TypeError: countOccurrences is not a function
Ludwig Magnusson
@TheLudd
Apr 23 2015 16:23
@airbuggy You have supplied countBy with two arguments so countOccurrences is indeed not a function. It is likely a number
Eugene Lerman
@airbugg
Apr 23 2015 16:26
also, i'm trying to make this a generic as possible and place it in a separate module for others at work to use, but i'm not at all as to what would be the preferred\idiomatic way to do it in functional js. I'm not using node/browserify/etc so these modules should be in vanilla js. anyone has any quick tips/pointers/general guidelines? (:
@TheLudd you're right. I see the problem. however how else can i pass the concatenated array to countBy?
Hardy Jones
@joneshf
Apr 23 2015 16:45
@airbuggy try writing it with explicit arguments, I think you'll see what the problem is there
also, atIndex == R.nth yes?
Eugene Lerman
@airbugg
Apr 23 2015 17:33
@joneshf thanks for the advice! finally managed to crack it: var result = R.compose(R.countBy(R.identity), R.chain(R.nth(1)));
Hardy Jones
@joneshf
Apr 23 2015 17:43
@airbuggy cool!
it seems like R.count = R.countBy(R.identity) would be useful.
Eugene Lerman
@airbugg
Apr 23 2015 19:39
@joneshf you're right. is there a builtin function in Ramda that takes in two or more objects and iterates over their members with a function call?
(for my purpose, i'd like to find out the ratio between a certain string appearing at a certain position and the total amout of times it appears, in any position)
is there a simple way to achieve this using ramda?
Hardy Jones
@joneshf
Apr 23 2015 20:09
I don't quite understand what you're asking for, do you want to apply a function to each value in an object?
or do you want to apply it to each key?
or both?
Hardy Jones
@joneshf
Apr 23 2015 20:18
hmm
should match return null ever? Doesn't it make more sense for it to return [] for no matches?
Eugene Lerman
@airbugg
Apr 23 2015 20:21
Sorry. just re-read it myself, very unclear (:
I have two object. I want to iterate over both, and whenever I find two keys that appear in both, say 'key1', i'd like to perform something like object1.key1 \ object2.key1
I know I can achieve this with lodash, using _.merge. Ramda's merge only works on lists, and does't accept a callback function.
Hardy Jones
@joneshf
Apr 23 2015 20:26
oh, I see.
so you want a mergeBy :: (v1 -> v2 -> v3) -> {k: v1} -> {k: v2} -> {k: v3} or so?
I don't know if something already exists
but you can roll your own
Brandon Wilhite
@JediMindtrick
Apr 23 2015 20:28
lol...those haskell-style signatures show up everywhere now
nothing wrong with it though
Eugene Lerman
@airbugg
Apr 23 2015 20:29
(could you please explain how to this notation, btw? i'm struggling lol)
how to read*
Hardy Jones
@joneshf
Apr 23 2015 20:30
@airbuggy what's your background? perhaps I can translate into something a bit more familiar
Eugene Lerman
@airbugg
Apr 23 2015 20:31
i'm a bioinformatics graduate. never took scheme or functional programming :\
Hardy Jones
@joneshf
Apr 23 2015 20:32
@airbuggy oh, then forget what i wrote, it's just a terser way of saying exactly what you wanted
Eugene Lerman
@airbugg
Apr 23 2015 20:32
is it anything like function signatures in first-order logic theory?
if you don't mind, i'd actually like to understand how to use this kind of notation. seems way simpler than english lol
Brandon Wilhite
@JediMindtrick
Apr 23 2015 20:33
I wouldn't mind to see it myself...check my answer so to speak
something C-ish maybe @airbuggy ?
or just plain ol' js
Hardy Jones
@joneshf
Apr 23 2015 20:36
@airbuggy yes, it's derived from that, the notation just drops any quantifiers, and changes each * into a ->
Scott Sauyet
@CrossEye
Apr 23 2015 20:38
@airbuggy: a recent discussion in #1035 may help explain this notation. (Ignore the first several messages, which are too specific. )
Brandon Wilhite
@JediMindtrick
Apr 23 2015 20:38
Would you fellows mind if I checked my understanding with an attempted translation?
Scott Sauyet
@CrossEye
Apr 23 2015 20:39
I'd love it. Here or on that issue, or in the wiki...
Brandon Wilhite
@JediMindtrick
Apr 23 2015 20:39
C#, so verbose...
KeyValuePair<string,T> mergeBy(Func<T,T,T> mergeFunc, KeyValuePair<string,T> v1, KeyValuePair<string,T> v2)
Hardy Jones
@joneshf
Apr 23 2015 20:39
@airbuggy so something like plus, where you have ∀x, y, z ∈ N (x * y) -> z would be rewritten as x -> x -> x, or so
@JediMindtrick pretty much, you'd want the values to be be able to be different though ... Func<T, U, V> mergeFunc ... and so on
of course in js, it doesn't matter
Eugene Lerman
@airbugg
Apr 23 2015 20:42
@joneshf @CrossEye Thanks guys! much clearer now(:
Brandon Wilhite
@JediMindtrick
Apr 23 2015 20:43
so question...in this bit here (v1 -> v2 -> v3)
does the fact that they are 1, 2, 3 mean they must be different types or that they can be different types
just to solidify
Hardy Jones
@joneshf
Apr 23 2015 20:43
can
Brandon Wilhite
@JediMindtrick
Apr 23 2015 20:43
k
thanks
Hardy Jones
@joneshf
Apr 23 2015 20:45
you could express that they must be different, it'd just take some more complex types.
and a very strong system to back itup
Brandon Wilhite
@JediMindtrick
Apr 23 2015 20:45
and generally....wherever we have -> between two symbols we can curry from the first to the second?
Hardy Jones
@joneshf
Apr 23 2015 20:46
anyway, @airbuggy i'm not seeing anything right away that gives you a mergeBy sort of functionality.
so you'd probably have to roll your own
a -> b is just notation for a function from a to b
and since -> is right associative, we usually leave off the parens
so a -> b -> c means the same thing as a -> (b -> c)
Brandon Wilhite
@JediMindtrick
Apr 23 2015 20:49
got it, thanks! sorry if I interrupted @airbuggy
Hardy Jones
@joneshf
Apr 23 2015 20:49
so a -> (b -> c) is a function from a to b -> c, or it's a function that takes an a, and returns a function that takes a b and returns a c.
Eugene Lerman
@airbugg
Apr 23 2015 20:55
@joneshf okay, so it's just like regular function notation, just without explicitly stating if a variable is a function itself (and the parens are omitted because of currying, am i correct?)
Scott Sauyet
@CrossEye
Apr 23 2015 20:57
But JS is not Haskell, and functions can take more than one parameter. So a -> b -> c -> d in Ramda is a function that can be called in any of these ways: f(a, b, c), f(a, b)(c), f(a)(b, c), or f(a)(b)(c), in each case returning a d.
Eugene Lerman
@airbugg
Apr 23 2015 21:00
thank you, guys!
Scott Sauyet
@CrossEye
Apr 23 2015 21:01
And damn it's hard enough to type in my mobile, never mind on a bouncing bus!
Scott Sauyet
@CrossEye
Apr 23 2015 21:19
mergeWith might have some interesting API questions. There are three cases. Key is only in base object. Key is only in extension object. Key is in both. Should the user supply a single function that could handle the appropriate combination of null / undefined values? Or should she supply three separate functions?
And it seems likely to lead to screwy behavior with non-associative functions.
Hardy Jones
@joneshf
Apr 23 2015 21:33
why would you need to handle those cases outside of the implementation?
Shouldnt it be merge === mergeWith(R.flip(R.always))?
since it's really that merge is a right biased union
so if the key exists in only one of the two obejcts, then it result should just have that value
you just want to change the behavior of the tie breaking in the union
merge breaks ties by last one wins
Hardy Jones
@joneshf
Apr 23 2015 21:38
mergeWith would break ties by a user supplied way
I think the cases you mentioned give rise to the other "set" style of operations
Hardy Jones
@joneshf
Apr 23 2015 21:44
if you're concerned with a key only being in one object and not both objects, then you're talking about set difference. If you want it to be in both, you're talking about set intersection. And if you want it to be in either (this is merge) you're talking about union.
of course, those are just approximations to the behavior, since we're talking about js objects and not sets.
Scott Sauyet
@CrossEye
Apr 23 2015 21:58

I was under the impression that mergeWith was supposed to supply a function other than 'pick one of the two', something that combined the two values in some way. If that's not what's wanted, say mergeWith(max), then my concerns are unfounded. But if the idea included mergeWith(concat):

mergeWith(concat, {a: 'foo', b: 'baz'}, {a: 'bar', b: 'qux'}); 
//=> {a: 'foobar', b: 'bazqux'}

then I think there's a lot more to decide.

Hardy Jones
@joneshf
Apr 23 2015 22:32
right, that's whati was assuming as well
picking one of two is a specific binary function
namely R.always or R.flip(R.always)
Hardy Jones
@joneshf
Apr 23 2015 22:56
Scott Sauyet
@CrossEye
Apr 23 2015 23:39
@joneshf: Yes, that's what I would assume would be the most likely, and concat turned out not to be a very good example. http://bit.ly/1yUGtp8 shows another function that doesn't have an obvious behavior if one object is missing the key: (x, y) => (2 * x - y). Sure we can default to x or y. Or should we default to 2 * x and -y? Something else? It just doesn't seem clear from the outside how to do it. We can simply make the call, but it's not clear to me that we should.
Hardy Jones
@joneshf
Apr 23 2015 23:58

I get what you're suggesting. I think it's a different problem though. Look at the array versions,

  • union makes the decision to keep either value if it exists,
  • intersect makes the decision to only keep values that exist in both,
  • difference makes the decision to only keep values that are in the first but not the second.

I feel like parallels can be drawn to object versions.

  • mergeBy is like union in that, if either object has the key, the value is kept, but if both have the key, a function is used to show how to "merge" the values.
  • Something could be made similar to intersect where if the two objects have the same key, then a function is used to "intersect" the values, but if one is missing, then the key/val is not in the result.
  • And something similar for difference could be made where if the first object had a key, but the second doesn't, then keep the value, otherwise drop the key/val.