for / list是否做不必要的逆转?

时间:2018-09-30 01:01:39

标签: racket list-comprehension reverse for-comprehension cons

我第一次在宏步进器中闲逛,发现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的习惯。有没有更有效的方式按“转发”顺序创建列表(即,所评估的最后一项是列表中的最后一项)?

1 个答案:

答案 0 :(得分:1)

从Git的历史来看,我发现committed是避免for/list避免使用reverse的一种方式,但it didn't work是由于与可能会触发的连续性之间的微妙交互四次时间行为。 (我想知道即将到来的Chez Scheme后端迁移是否可能意味着“当有一天Racket能够更好地实施延续性时”实际上就会来临。)

您可以按照“转发”顺序构建列表,方法是,如第一条提交消息中所述,“ cons进入递归调用”。 Tail RecursionRecursion versus Iteration的“球拍指南”部分实际上详细讨论了map风格和for/fold风格方法之间的取舍。

此外,与以后在Stack Overflow上讨论的情况相比,Racket社区更倾向于生活在非常活跃和友好的racket-users mailing list上,并且在某种程度上是Slack渠道,以供将来参考。