【问题标题】:Iterative map in scheme方案中的迭代映射
【发布时间】:2014-05-07 23:11:59
【问题描述】:

我正在观看 SICP 视频讲座,我来到了一个部分,导师正在展示使用列表的程序,所以,这里是其中之一:

(define (map p l)
   (if (null? l) 
       (list)
       (cons (p (car l))
                    (map p (cdr l)))))

我想问的是:有没有办法以迭代的方式定义map,或者cons需要执行惰性求值对吗?

【问题讨论】:

  • 什么意思? cons 不涉及懒惰。
  • @molbdnilo 他希望它像 Haskell 一样是尾递归或惰性的。

标签: recursion scheme lisp iteration sicp


【解决方案1】:

您的原始代码几乎是尾递归的.. 唯一使它不是的是cons 部分。如果 Scheme 对 TRMC optimization 的要求与 TCO 的要求相同,则您可以保留您的代码原样,并且实现会使它对您来说是尾递归的。

由于这不是我们需要进行自己的 TRMC 优化的要求。通常在循环中迭代列表并使用累加器进行尾递归时,您会以相反的顺序获得结果,因此您可以进行反向线性更新:

(define (map proc lst)
  (let loop ((lst lst) (acc '()))
    (cond ((null? lst) (reverse! acc) acc)
          (else (loop (cdr lst) 
                      (cons (proc (car lst)) acc))))))

或者您可以一次完成所有操作:

(define (map proc lst)
  (define head (list 1))
  (let loop ((tail head) (lst lst))
    (cond ((null? lst) (cdr head))
          (else (set-cdr! tail (list (proc (car lst))))
                (loop (cdr tail) (cdr lst))))))

现在在这两种情况下,您只改变过程本身创建的结构,因此对于用户来说,它可能会以与您的示例相同的方式实现。

当你在你的实现中使用像map 这样的高阶过程时,它可能已经被这样实现了。通过将提供的map 的性能与具有很长列表的不同实现进行比较,很容易发现。执行之间的差异将告诉您它是否是 TRMCO 或提供的 map 可能已如何实现。

【讨论】:

  • “任何提及 TRMC 都会自动获得我的支持”。 :) 只是认为它是 first described in 1974 并且从那时起(在 Scheme 上下文中)一直被忽视!!
【解决方案2】:

你需要接受递归才能总体上欣赏SICP和Scheme,所以试着习惯它,你以后会欣赏的,承诺。

但是,你可以:

(define (iterative-map f lst)
  (define res null)
  (do ((i (- (length lst) 1) (- i 1))) ((= i -1))
    (set! res (cons (f (list-ref lst i)) res)))
  res)

(iterative-map (lambda (x) (+ x 1)) '(1 3 5))
=> '(2 4 6)

但是如果可以避免的话,使用set! 被认为是不好的风格。

在 Racket 中,您有一组更优雅的循环:

(define (for-map f lst)
  (for/list ((i lst))
    (f i)))

(for-map add1 '(1 3 5))
=> '(2 4 6)

【讨论】:

  • 谢谢。不要认为我有递归问题(我实际上很喜欢它)我只是好奇如何以另一种方式实现它。
  • 如果你想拥抱Scheme,你需要避免突变。 (糟糕!)
  • @leppie 没有解决方案可以让map 在没有突变的情况下进行尾递归,所以每个答案都会有。
  • @Sylwester:你使用的唯一突变是reverse!(在这种情况下是安全的),所以我不明白你的意思。
  • @leppie 这不是这里不好的突变,而是用于反向迭代列表的list-ref。我的观点是你需要一个高效的map 的突变来补偿单链表的性质。我的第二个版本使用set-cdr!,它的速度是第一个和 10 倍 OP 原始示例的两倍。
猜你喜欢
  • 1970-01-01
  • 2018-10-07
  • 1970-01-01
  • 2022-10-23
  • 2010-11-29
  • 1970-01-01
  • 2011-05-29
  • 2011-12-29
  • 1970-01-01
相关资源
最近更新 更多