Javascript 使用converge生成列表的所有旋转时出现意外结果
我正在尝试获取列表的所有旋转Javascript 使用converge生成列表的所有旋转时出现意外结果,javascript,functional-programming,ramda.js,Javascript,Functional Programming,Ramda.js,我正在尝试获取列表的所有旋转v。因此,在旋转的定义中,我使用翻转版本的rotateLeft作为第一个分支函数(为了首先接受列表),然后是一个返回列表的函数[0,1,2,…,v.length-1],其中映射作为收敛函数 const {curry,mathMod,pipe,splitAt,reverse,unnest,converge,map,flip,length,times,identity} = require("ramda"); const v = [1,2,3,4]; const ro
v
。因此,在旋转
的定义中,我使用翻转版本的rotateLeft
作为第一个分支函数(为了首先接受列表),然后是一个返回列表的函数[0,1,2,…,v.length-1]
,其中映射
作为收敛函数
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
。是这样吗?
那么为什么旋转(v)不返回相同的结果呢
使用reduce
受vanilla JS版本的启发,我提出了以下reduceRotations
函数,它没有明显地使用map
的索引参数或递归。然后,当然,我把它翻译成了香草拉姆达,完全没有要点
还有一个
以下等效功能使用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
]);
这是因为
converge
将提供给它的最长函数的arity作为其arity
因此,由于flip(rotateLeft).length/=>2
和pipe(length,times(identity))/=>1
,旋转将具有长度2。但你显然想要一元函数。最简单的修复方法是将翻转(rotateLeft)
放入一元数
:
const rotateLeft=curry((n,vet)=>{
常数i=数学模型(n,纵向长度);
回流管(
第(i)款,
相反,
不耐烦
)(兽医);
});
常数旋转=收敛(映射[
一元(翻转(旋转英尺)),
管道(长度、次数(标识))
])
常数v=[1,2,3,4];
控制台日志(
轮换(五)
)
const{curry,mathMod,pipe,splitAt,reverse,unnest,converge,map,一元数,flip,length,times,identity}=R
通过这种简单的递归实现的旋转
证明,有时由大量小函数组成的无点代码不值得额外的头痛-
const rotations=([x,…xs],count=0)=>
计数>xs.length
? []
:[[x,…xs],…旋转([…xs,x],计数+1)]
控制台日志(旋转([1,2,3]))
// [ [ 1, 2, 3 ], [ 2, 3, 1 ], [ 3, 1, 2 ] ]
控制台日志(旋转([1,2,3,4]))
//[[1,2,3,4],[2,3,4,1],[3,4,1,2],[4,1,2,3]。
使用地图切片的出色实现
!我想我不会想到这个:D@user633183:嗯,它利用了Array.prototype.map
的额外索引参数(通常很不幸)。这感觉有点像滥用map
。哦,谢谢!算术。。。好吧,现在说得通了!和往常一样回答得很好!。我正要写一个递归版本,这时我想到了我的map
答案,然后就不费事了。干得好!尽管如此,我的目标是操作之前定义的rotateLeft
,尽可能多地使用Ramda函数和无点合成,主要是作为练习。否则,我可能会写一些和你在这里做的非常相似的东西。。。还可以查看我的旋转的替代版本
!也许甚至比无点版本更干净:constrotate=lift(append)(head(v),tail(v))
是无点版本:constrotate=lift(append)(head,tail)
。(可选的converge(append,[head,tail])
感觉不那么优雅,而且肯定不那么标准。)
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
]);