I'm trying to get all the rotations of the list v
. So, in the definition of rotations
, I use the flipped version of rotateLeft
as the first branching function (in order to accept the list first) and then a function that returns the list [0, 1, 2, ..., v.length-1]
, with map
as the converging function.
const {curry,mathMod,pipe,splitAt,reverse,unnest,converge,map,flip,length,times,identity} = require("ramda");
const v = [1,2,3,4];
const rotateLeft = curry((n,vet) => {
const i = mathMod(n,vet.length);
return pipe(
splitAt(i),
reverse,
unnest
)(vet);
});
const rotations = converge(map,[
flip(rotateLeft),
pipe(length,times(identity))
]);
rotations(v);
However, this doesn't return what I expected. Instead, it works fine if I rewrite that as follows:
map(flip(rotateLeft)(v),
pipe(length,times(identity))(v));
// gives [[1,2,3,4],[2,3,4,1],[3,4,1,2],[4,1,2,3]]
As I understand, converge
applies the two branching functions to v
and then feeds the results as arguments to map
. Is that right?
So why doesn't rotations(v)
return the same thing?
Code
More concise version using reduce
Inspired by your versions in vanilla JS, I've come up with the following reduceRotations
function, which doesn't use the index parameter of map
or recursion in an obvious way. Then, of course, I translated that into vanilla Ramda, in a totally point-free fashion. :)
const {converge,reduce,always,append,pipe,last,head,tail,identity,unapply} = require("ramda");
const reduceRotations = (v) => {
const rotate = (v) => append(head(v),tail(v));
return reduce(
(acc,_) => append(rotate(last(acc)),acc),
[v],
tail(v)
);
};
const pointFreeRotations =
converge(reduce,[
always(converge(append,[
pipe(last,converge(append,[head,tail])),
identity
])),
unapply(identity),
tail
]);
Code
Yet another one
The following equivalent functions employ scan
instead of reduce
.
const {converge,scan,always,append,head,tail,identity} = require("ramda");
const scanRotations = (v) => {
const rotate = (v) => append(head(v),tail(v));
return scan(rotate,v,tail(v));
};
const scanPointFreeRotations =
converge(scan,[
always(converge(append,[head,tail])),
identity,
tail
]);
Code
This is because converge
takes as its arity the arity of the longest function supplied to it.
So, since flip(rotateLeft).length //=> 2
and pipe(length,times(identity)) //=> 1
, rotations will have length 2. But you clearly want a unary function. The easiest way to fix it is to simply wrap flip(rotateLeft)
inside unary
:
const rotateLeft = curry((n,vet) => {
const i = mathMod(n,vet.length);
return pipe(
splitAt(i),
reverse,
unnest
)(vet);
});
const rotations = converge (map, [
unary ( flip (rotateLeft) ),
pipe ( length, times(identity) )
])
const v = [1,2,3,4];
console .log (
rotations (v)
)
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script><script>
const {curry, mathMod, pipe, splitAt, reverse, unnest, converge, map, unary, flip, length, times, identity} = R </script>
Also note that this doesn't really require all of Ramda's machinery. It's pretty easy to do this in vanilla JS:
const rotations = v => v .map ( (_, i) => v .slice (i) .concat ( v .slice(0, i) ) )
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With