These are chat archives for ramda/ramda

5th
Oct 2015
boxofrox
@boxofrox
Oct 05 2015 00:00
now if only it had vim keybindings
James Campos
@aeosynth
Oct 05 2015 02:09
is there an assocPath where i can supply a function instead of a value?
is there an equivalent to adjust for objects?
boxofrox
@boxofrox
Oct 05 2015 02:19

I think you want lenses.

var myObj = { a: { b: 2 } };
var aLens = R.lensProp('a');
var bLens = R.lensProp('b');

var overA = R.over(aLens);
var overB = R.over(bLens);

var myFn = R.inc;

console.log(overA(overB(myFn))(myObj));  //=> { a: { b: 3 } }

Not as pretty as assocPath, but it allows you to manipulate deep values with functions.

boxofrox
@boxofrox
Oct 05 2015 02:36
@aeosynth, even better. https://tonicdev.com/boxofrox/ramda-lenspath
I honestly can't believe how simple that turned out. FP must be growing on me.
James Campos
@aeosynth
Oct 05 2015 02:37
thanks, i'm still reading through the docs
Scott Sauyet
@CrossEye
Oct 05 2015 03:04
Do note: R.compose (aLens, bLens)
Which doesn't take away from your alternate formulation, but does simplify the original one.
boxofrox
@boxofrox
Oct 05 2015 03:07
Did not know. Thanks @CrossEye
boxofrox
@boxofrox
Oct 05 2015 03:29

In my attempts to write point-free code with Ramda, I've found myself stumbling over the need to reuse arguments more than once.

Take the lensPath I just wrote for example.

lensPath = function (path) {
  return R.lens(R.path(path), R.assocPath(path));
};

Here I need to use path as input to two functions. Stumbling around the docs on point-free FP, I haven't run into any discussion about this.

In the meantime, I keep adding a replicate function to my projects that applies one argument N times.

var replicate = function (n, f, x) {
  return R.apply(f, R.repeat(x, n));
}

So I can rewrite lensPath as

// [String] -> Lens s a
lensPath = replicate(2, R.converge(R.lens, R.path, R.assocPath));

At least, I think I did that right. Anyway, I was wondering if anyone knew of replicate by a different name or had any references for similar tricks. Sorry for the long post.

Raine Virta
@raine
Oct 05 2015 06:22
the first lensPath is more readable, at cost of 2 more lines. conversely, PF lensPath is more concise, but at cost of introducing two new functions reader needs to understand
Patrick Gaubatz
@pgaubatz
Oct 05 2015 08:26

Hi! Let's suppose we've got the following code:

function values (arr) {
  return arr;
}

function keys (values) {
  return R.map(function (value) {
    return 'v' + value;
  }, values);
}

function transform (arr) {
  var v = values(arr);
  return R.zipObj(keys(v), v);
}

transform(['a', 'b']); // -> { va: 'a', vb: 'b' }

Is there any elegant way of defining transform() without using the temporary variable v?

Raine Virta
@raine
Oct 05 2015 08:27
what is the purpose of values()?
Patrick Gaubatz
@pgaubatz
Oct 05 2015 08:30
values() is just there to illustrate the concept. My actual code looks like this:
var values = R.pipe(
  R.split('_'),
  R.takeLast(R.length(RKA_SEQ))
);
R.zipObj(keys(values(arr)), values(arr)) runs values() twice which is not really desireable...
Patrick Gaubatz
@pgaubatz
Oct 05 2015 08:36
so in other words: I want to use R.zipObj() and I have keys() and values() that generate the arrays required for R.zipObj()
in my concrete example keys() solely depends on the output of values()
Raine Virta
@raine
Oct 05 2015 08:38
const R = require('ramda');

const objFromKeys = R.curry((fn, keys) =>
  R.zipObj(keys, R.map(fn, keys)))

const mapKeys = R.curry((fn, obj) =>
  R.fromPairs(R.map(R.adjust(fn, 0), R.toPairs(obj))));

const transform =
  R.pipe(objFromKeys(R.identity),
         mapKeys(R.add('v')));

transform(['a', 'b']); // { va: 'a', vb: 'b' }
Patrick Gaubatz
@pgaubatz
Oct 05 2015 08:42
@raine Thanks a lot! Obviously your code works :)
@raine I fear that trying to fully understand how it works will require some time... ;)
the examples might help
Patrick Gaubatz
@pgaubatz
Oct 05 2015 08:47
@raine thanks a lot!
Conor Linehan
@ConorLinehan
Oct 05 2015 10:50
Hi :) suppose I had the following structure var cols = [[7],[7],[7],[7]] and I wanted to map it to rows where rows is the first element from each cols what would be a more "ramda" way of doing it as opposed to iterating through elements?
Raine Virta
@raine
Oct 05 2015 10:53
@ConorLinehan for example?
Conor Linehan
@ConorLinehan
Oct 05 2015 10:58
@raine I suppose something like this
var rows = [];
    var length = columns[0][0].length;
    for (var i = 0; i < length; i++) {
      var arr = [];
      for (var j = 0; i < columns.length; i++) {
        arr.push(columns[j][i]);
      }
    }
Raine Virta
@raine
Oct 05 2015 10:59
but what is the expected value of rows?
Conor Linehan
@ConorLinehan
Oct 05 2015 11:01
rows = [[],[],[],[]] where the first array would be equal to the first element in each of thecols array
Scott Christopher
@scott-christopher
Oct 05 2015 11:22
@ConorLinehan Something like this perhaps?
var transpose = list => {
  if (R.isEmpty(list)) return list;
  var x_xs = R.head(list);
  var xss  = R.tail(list);
  if (R.isEmpty(x_xs)) return transpose(xss);
  var y_ys = R.prepend(R.head(x_xs), R.map(R.head, xss));
  var yss  = transpose(R.prepend(R.tail(x_xs), R.map(R.tail, xss)));
  return R.prepend(y_ys, yss);
}

transpose([[1,2,3,4],[5,6,7,8]]); //=> [[1, 5], [2, 6], [3, 7], [4, 8]]
Just be mindful that it's recursive, so it'll fall over for large lists.
Denis Stoyanov
@xgrommx
Oct 05 2015 11:34

@scott-christopher I think this is also working example:

var a = [[1,2,3,4],[5,6,7,8]];
R.zip(R.head(a), R.flatten(R.tail(a)));

But I don't understand why R.tail(a) don't return just [5,6,7,8] and I should use flatten

Raine Virta
@raine
Oct 05 2015 11:36
because tail has signature [a] -> [a]
Scott Christopher
@scott-christopher
Oct 05 2015 11:38
also try it with lists of different shapes, like:
[[1,2,3,4],[5,6,7,8],[9,10,11,12]]
Denis Stoyanov
@xgrommx
Oct 05 2015 11:38
@raine But tail from [[1], [2]] probably should be [2]
Scott Christopher
@scott-christopher
Oct 05 2015 11:39
R.tail([[1],[2]]) == [[2]]
It just so happens that there is only one element.
e.g. R.tail([[1],[2],[3]]) == [[2],[3]]
Denis Stoyanov
@xgrommx
Oct 05 2015 11:54
@scott-christopher Take a look at:
var a = [[1,2,3,4],[5,6,7,8], [4,5,6,7], [40,56,66,47]];
R.reduce(R.zipWith((...args) => R.flatten(args)), R.head(a), R.tail(a));
Scott Christopher
@scott-christopher
Oct 05 2015 11:56

If you're handling a mix of different sized lists, my example above will spit out undefined for "missing" elements:

transpose([[1,2,3],[4,5],[],[6,7,8,9]]);
// [ [ 1, 4, undefined, 6 ],
//  [ 2, 5, undefined, 7 ],
//  [ 3, undefined, undefined, 8 ],
//  [ 9 ] ]

You can switch out R.map(R.head, xss) for:

R.reduce((acc, x) =>
  R.isEmpty(x) ? acc : R.append(R.head(x), acc), [], xss)

and it will evalute to:

transpose([[1,2,3],[4,5],[],[6,7,8,9]]);
// [ [ 1, 4, 6 ], [ 2, 5, 7 ], [ 3, 8 ], [ 9 ] ]
Scott Christopher
@scott-christopher
Oct 05 2015 12:17
@xgrommx: That's definitely much more succinct :)
You can swap out the R.flatten(args) for:
xss => R.reduce(R.zipWith(R.flip(R.append)), R.map(R.of, R.head(xss)), R.tail(xss))
and for bonus mindbending points-free points:
R.converge(R.reduce(R.zipWith(R.flip(R.append))), R.compose(R.map(R.of), R.head), R.tail)
Conor Linehan
@ConorLinehan
Oct 05 2015 12:31

@scott-christopher @raine @xgrommx Thanks :) It works with two columns, but I need the same with multiple? As in

transpose([[1,2,3,4],[5,6,7,8]],[9,10,11,12]); // [1,5,9] , [2,6,10]

Here’s what the object i’m working on looks like

Object {0: Array[7], 1: Array[7], 2: Array[7], 3: Array[7], 4: Array[7], 5: Array[7], 6: Array[7], 7: Array[7], 8: Array[7], 9: Array[7], 10: Array[7], 11: Array[7], 12: Array[7], 13: Array[7], 14: Array[7]}
Scott Christopher
@scott-christopher
Oct 05 2015 12:33
Is [[1,2,3,4],[5,6,7,8]],[9,10,11,12] meant to be two separate arrays?
Assuming you meant it as a single 3-element array, those functions will produce:
transpose([[1,2,3,4],[5,6,7,8],[9,10,11,12]]);
// [ [ 1, 5, 9 ], [ 2, 6, 10 ], [ 3, 7, 11 ], [ 4, 8, 12 ] ]
Conor Linehan
@ConorLinehan
Oct 05 2015 12:35
Sorry no there all in one array. I basically have an array of columns of a table cols and I’m trying to get an array of rows from that

Like if you were thnking of an excell sheet I’m looking for

[
[A1,B1,C1,D1],
[A2,B2,C2,D2],
[A3,B3,C3,D3]
]

And I’m giving it the following

[
[A1,A2,A3,A4],
[B1,B2,B3,B4],
….
]
Conor Linehan
@ConorLinehan
Oct 05 2015 13:00
@scott-christopher Sorry my bad that works perfect :) my problem was
var cols = R.merge(learnerArr,lessonArr); // {}

// Should be
var cols = R.prepend(learnersArr,lessonArr);
Scott Christopher
@scott-christopher
Oct 05 2015 13:01
glad to hear :)
Conor Linehan
@ConorLinehan
Oct 05 2015 13:01
Though I was looking at R.zip and that doesn’t work? I thought they should be the same thing?
Frederik Krautwald
@Frikki
Oct 05 2015 13:16
Hi all, is Fantasy Land stuff discussed here?
Martin Algesten
@algesten
Oct 05 2015 13:18
@Frikki it is indeed
Raine Virta
@raine
Oct 05 2015 13:18
fantasyland has its own room though
Frederik Krautwald
@Frikki
Oct 05 2015 13:19
@raine got it!
I guess what I’d like to know is if any of the ramda libraries have contracts, e.g.:
var x = func(x); // returns x if x is a function; otherwise throws TypeError
var y = string(y);  // returns y if y is a string; otherwise throws TypeError
Raine Virta
@raine
Oct 05 2015 13:24
Sanctuary has some kind of typechecking
Scott Sauyet
@CrossEye
Oct 05 2015 13:42
@boxofrox: coverge exists to handle much the same case as your replicate. You might need an additional unary wrapper with it.
hemanth @hemanth just made http://h3manth.com/npm-janitor/
hemanth.hm
@hemanth
Oct 05 2015 13:43
helps to clean package.json files of all your node modules.
Scott Sauyet
@CrossEye
Oct 05 2015 13:43
var lensPath = R.converge(R.lens, R.unary(R.path), R.unary(R.assocPath));
Hardy Jones
@joneshf
Oct 05 2015 14:08
@Frikki I don't think anything throws intentionally
thankfully.
Frederik Krautwald
@Frikki
Oct 05 2015 14:11
@joneshf Hi there :D Exceptions are side effects, true. I looked at Sanctuary, but didn’t quite see how I can use it for contracting types.
Raine Virta
@raine
Oct 05 2015 14:11
you can't
Hardy Jones
@joneshf
Oct 05 2015 14:11
What are you actually trying to achieve?
new blag that mentions ramda towards the end: https://joneshf.github.io/programming/2015/10/04/Cleanup-Algorithm.html
Frederik Krautwald
@Frikki
Oct 05 2015 14:13
I want to ensure that a given argument is of a specific type. For example, I often require Rx.Observables as arguments, and I need to ensure that it actually is an Observable.
Hardy Jones
@joneshf
Oct 05 2015 14:14
How can you ensure that?
in theory, I guess, not necessarily in actuality.
type check?
interface check?
Rather, why do you want to ensure that?
Frederik Krautwald
@Frikki
Oct 05 2015 14:15
ATM, I do that with my own implementation, e.g.:
(observable$) => {
  const obs$ = instanceOf(Rx.Observable)(observable$);
  ...
}
Hardy Jones
@joneshf
Oct 05 2015 14:16
why do you need it to be an Observable?
Frederik Krautwald
@Frikki
Oct 05 2015 14:17
Because I cannot do undefined.flatMap() etc.
Hardy Jones
@joneshf
Oct 05 2015 14:18
Why not check for the methods that are used?
if you use flatMap and sample within the function, why not check for those methods alone?
Frederik Krautwald
@Frikki
Oct 05 2015 14:18
Because it is boilerplate code
It’s not an issue at all. I was just wondering whether Ramda or a Ramda library had a similar implementation, because I already use Ramda.
Hardy Jones
@joneshf
Oct 05 2015 14:20
If you build your contracts to an interface, you get more reuse and generally better code though.
Oh
Frederik Krautwald
@Frikki
Oct 05 2015 14:21
What do you mean "an interface"?
Martin Algesten
@algesten
Oct 05 2015 14:22
this discussion can be enlightening. fantasyland/fantasy-land#92
there isn't a great way of detecting fantasy-land compatible structures. but it is being considered.
Hardy Jones
@joneshf
Oct 05 2015 14:24
When you do an instanceof check you're restricting which objects can be used to a very small subset. Also objects in different contexts will fail that check even if they look like they should pass. If instead you check that the object has certain methods, you worry not about whether it's in a specific part of the hierarchy, or whether it was created in a certain domain. All you care is if you can invoke the methods on the object passed in.
In any case, I'm not sure if someone wrote a contract library specific to ramda.
Frederik Krautwald
@Frikki
Oct 05 2015 14:31
@joneshf That is true, and I will consider that approach in regards to Objects. I have other uses for when contracts should be applied. One is that the consumer of my code specifies an Observable that emits an Object of properties. To ensure that the Object of props adhere to certain types, it is passed through a function that predicates each property according to a matching definition.
@algesten Was that link to me?
Hardy Jones
@joneshf
Oct 05 2015 14:34
Observables are objects too ;)
Frederik Krautwald
@Frikki
Oct 05 2015 14:34
@joneshf Yes they are
And I’ll consider
boxofrox
@boxofrox
Oct 05 2015 18:46
@CrossEye , ah yes, I did fubar that use of converge in my example. Thanks for pointing out unary; learned something new.