[英]How do collector functions work in Scheme?
我無法理解 Scheme 中收集器函數的使用。 我正在使用“The Little Schemer”一書(由 Daniel P. Friedman 和 Matthias Felleisen 撰寫)。 一個帶有一些解釋的綜合示例將極大地幫助我。 以下代碼段是使用收集器函數的函數示例:
(define identity
(lambda (l col)
(cond
((null? l) (col '()))
(else (identity
(cdr l)
(lambda (newl)
(col (cons (car l) newl))))))))
...以示例調用為(identity '(abc) self)
和self-function
為(define self (lambda (x) x))
。 identity
函數返回給定的列表l
,因此給定調用的輸出將是(abc)
。 使用的確切語言是 R5RS Legacy 語言。
鑒於identity
定義中如何定義這些“收集器”函數,調用
(identity xs col)
對於任何列表xs
和一些“收集器”函數col
,相當於調用
(col xs)
所以相同的列表將被“返回”,即傳遞給它的參數“收集器”/繼續函數col
。 這就解釋了它的名字, identity
,然后。
為了比較, reverse
可以編碼為
(define reverse ; to be called as e.g. (reverse l display)
(lambda (l col)
(cond
((null? l) (col '())) ; a reversed empty list is empty
(else (reverse (cdr l) ; a reversed (cdr l) is newl --
(lambda (newl) ; what shall I do with it when it's ready?
(col ; append (car l) at its end and let col
(append newl ; deal with it!
(list (car l))))))))))
這種編程風格被稱為continuation-passing 風格:每個函數都被傳遞一個“continuation”,假定它將傳遞其余計算的結果,因此原始的 continuation/collector 函數將傳遞最終結果最終。 每個收藏家的說法代表了未來的“結果”,它將接收和收集功能本身,然后指定它是如何被處理,然后。
不要被術語混淆:這些函數不是call/cc
函數捕獲的“延續”,它們是普通的 Scheme 函數,代表“接下來要做什么”。
定義可以理解為
identity :
to transform a list xs
with a collector function col,
is
| to call (col xs) , if xs is empty, or
| to transform (cdr xs)
with a new collector function col2
such that
(col2 r) = (col (cons (car xs) r)) , otherwise.
(或者我們可以用偽代碼編寫,如)
(identity list col) =
| empty? list -> (col list)
| match? list (x . xs) -> (identity xs col2)
where
(col2 r) = (col (cons x r))
col2
通過將(cons xr)
傳遞給前一個處理程序col
來處理其參數r
。 這意味着r
被轉換為(cons xr)
,但它不是作為值返回,而是被送入col
進行進一步處理。 因此,我們通過將新值(cons xr)
傳遞給前一個“收集器”來“返回”新值。
示例調用,作為說明:
(identity (list 1 2 3) display)
= (identity (list 2 3) k1)
; k1 = (lambda (r1) (display (cons 1 r1))) = display ° {cons 1}
= (identity (list 3) k2)
; k2 = (lambda (r2) (k1 (cons 2 r2))) = k1 ° {cons 2}
= (identity (list ) k3)
; k3 = (lambda (r3) (k2 (cons 3 r3))) = k2 ° {cons 3}
= (k3 '()) ; (((display ° {cons 1}) ° {cons 2}) ° {cons 3}) []
= (k2 (cons 3 '())) ; ((display ° {cons 1}) ° {cons 2}) [3]
= (k1 (cons 2 (list 3))) ; (display ° {cons 1}) [2,3]
= (display (cons 1 (list 2 3))) ; display [1,2,3]
= (display (list 1 2 3))
更新:在我最近喜歡使用的模式匹配偽代碼中,我們可以寫
identity [] col = col []
identity [a, ...d] col = identity d ( newl => col [a, ...newl] )
和
reverse [] col = col []
reverse [a, ...d] col = reverse d ( newl => col [...newl, a] )
希望它在視覺上非常明顯,幾乎不需要解釋!
我正在添加第二個答案,希望它可以澄清剩余的疑問,以防您有任何疑問(因為缺少“已接受”標記表明)。
在 Gerald J. Sussman 的聲音中,正如在 SICP 講座中聽到/看到的那樣,視頻在互聯網管道上隨處可見,我們可以在寫作時閱讀它,
(define identity
“身份”被定義為
(lambda
那個函數,當給定
(l col)
兩個參數, l
和col
,將
(cond
((null? l)
-- 如果(null? l)
為真 --
好的,這意味着l
是一個列表,注意
(col '()))
返回表達式的值(col '())
col
是一個函數,需要一個參數,作為一種可能是空列表, (else (identity (cdr l)
否則它將使用更新的值進行尾遞歸調用,一個是(cdr l)
,
(lambda (newl)
(col (cons (car l) newl)))))))
另一個是新構造的函數,這樣當它被調用時,它的參數為newl
(一個列表,正如對col
預期——因為它出現在相同的角色中,它必須遵循相同的約定),將依次使用由前綴(car l)
到列表newl
產生的非空列表調用函數col
。
因此,這個函數, identity
,遵循方程
( identity (cons (car l) (cdr l)) col )
==
( identity (cdr l) (lambda (newl) (col (cons (car l) newl))) )
和
( identity '() col )
==
( col '() )
描述一個迭代過程,這個過程將函數調用
(identity [a, b, c, ..., n] col )
進入通話
(col
(cons a (cons b (cons c ... (cons n '()) ... ))))
重新創建完全相同的列表,然后將其作為參數提供給已提供的函數col
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.