我正在尝试获取列表v
的所有轮换。因此,在rotations
的定义中,我将rotateLeft
的翻转版本用作第一个分支函数(以便首先接受列表),然后使用返回列表[0, 1, 2, ..., v.length-1]
的函数,其中map
为收敛函数。
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);
但是,这并没有返回我期望的结果。相反,如果我按如下所示重写它,则可以正常工作:
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]]
据我了解,converge
将两个分支函数应用于v
,然后将结果作为参数提供给map
。那正确吗?
那么,rotations(v)
为什么不返回相同的东西?
使用reduce
受您的 vanilla JS 版本启发,我提出了以下reduceRotations
函数,该函数不使用map
的index参数或一种明显的方式。然后,当然,我以完全没有意义的方式将其翻译为 vanilla Ramda 。 :)
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
]);
又一个人
以下等效函数使用scan
代替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
]);
答案 0 :(得分:4)
这是因为top_block_cls
将提供给它的最长函数的arity作为其arity。
因此,由于converge
和flip(rotateLeft).length //=> 2
,旋转的长度为2。但是您显然想要一元函数。解决此问题的最简单方法是将pipe(length,times(identity)) //=> 1
包裹在flip(rotateLeft)
内:
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)
)
还请注意,这实际上并不需要Ramda的所有机器。在香草JS中很容易做到这一点:
<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>
答案 1 :(得分:3)
通过rotations
的这种简单的递归实现来证明,有时由大量微型函数组成的无点代码根本不值得增加麻烦-
const rotations = ([ x, ...xs ], count = 0) =>
count > xs.length
? []
: [ [ x, ...xs ], ...rotations ([ ...xs, x ], count + 1) ]
console.log(rotations([1,2,3]))
// [ [ 1, 2, 3 ], [ 2, 3, 1 ], [ 3, 1, 2 ] ]
console.log(rotations([1,2,3,4]))
// [ [ 1, 2, 3, 4 ], [ 2, 3, 4, 1 ], [ 3, 4, 1, 2 ], [ 4, 1, 2, 3 ] ]
上面,销毁分配会创建许多中间值,但是我们可以使用稍微不同的算法来解决此问题-
const rotations = (xs = [], i = 0) =>
i >= xs.length
? []
: [ xs.slice(i).concat(xs.slice(0, i)) ].concat(rotations(xs, i + 1))
console.log(rotations([1,2,3]))
// [ [ 1, 2, 3 ], [ 2, 3, 1 ], [ 3, 1, 2 ] ]
console.log(rotations([1,2,3,4]))
// [ [ 1, 2, 3, 4 ], [ 2, 3, 4, 1 ], [ 3, 4, 1, 2 ], [ 4, 1, 2, 3 ] ]
像您一样定义辅助功能是要保持良好的卫生习惯。这也使我们的其他功能更具可读性-
const rotate = (xs = []) =>
xs.slice(1).concat(xs.slice(0, 1))
const rotations = (xs = [], i = 0) =>
i >= xs.length
? []
: [ xs ].concat(rotations(rotate(xs), i + 1))
console.log(rotations([1,2,3]))
// [ [ 1, 2, 3 ], [ 2, 3, 1 ], [ 3, 1, 2 ] ]
console.log(rotations([1,2,3,4]))
// [ [ 1, 2, 3, 4 ], [ 2, 3, 4, 1 ], [ 3, 4, 1, 2 ], [ 4, 1, 2, 3 ] ]