我第一次在宏步进器中闲逛,发现for/list
扩展为涉及alt-reverse
的代码。 for/list
是否将每个项目限制在一个空列表的前面,然后将其反转?看来效率很低。
我写了一个小测试:
(define (test n)
(time
(for/list ([x (in-range n)])
(list x x)))
(time
(for/fold ([result '()])
([x (in-range n)])
(cons (list x x) result)))
(void))
实际上,for/list
版的运行时间是for/fold
的150%,而没有reverse
的运行时间,差异显然完全是由于额外的垃圾收集造成的:
> (test 500000)
cpu time: 1059 real time: 2079 gc time: 940
cpu time: 614 real time: 1231 gc time: 550
> (test 500000)
cpu time: 1060 real time: 3889 gc time: 907
cpu time: 770 real time: 1363 gc time: 699
> (test 500000)
cpu time: 1035 real time: 2479 gc time: 917
cpu time: 736 real time: 2535 gc time: 651
听起来我不应该养成打电话for/list
的习惯。有没有更有效的方式按“转发”顺序创建列表(即,所评估的最后一项是列表中的最后一项)?
答案 0 :(得分:1)
从Git的历史来看,我发现committed是避免for/list
避免使用reverse
的一种方式,但it didn't work是由于与可能会触发的连续性之间的微妙交互四次时间行为。 (我想知道即将到来的Chez Scheme后端迁移是否可能意味着“当有一天Racket能够更好地实施延续性时”实际上就会来临。)
您可以按照“转发”顺序构建列表,方法是,如第一条提交消息中所述,“ cons
进入递归调用”。 Tail Recursion和Recursion versus Iteration的“球拍指南”部分实际上详细讨论了map
风格和for/fold
风格方法之间的取舍。
此外,与以后在Stack Overflow上讨论的情况相比,Racket社区更倾向于生活在非常活跃和友好的racket-users mailing list上,并且在某种程度上是Slack渠道,以供将来参考。