簡體   English   中英

方案中的迭代圖

[英]Iterative map in scheme

我正在觀看SICP的視頻講座,並且我來到了一個部分,那里的老師正在顯示處理列表的過程,因此,其中一個是:

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

我想問的是:是否有一種以迭代方式定義map的方法,或者cons需要懶惰的評估才能正確執行?

您的原始代碼幾乎是尾部遞歸的..唯一使它不行的是cons部分。 如果計划有平等的要求,對具有TRMC優化 ,因為它有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可能是如何實現的。

您需要接受遞歸才能大致了解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)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM