2009-12-08 41 views
6

我試圖理解示例代碼here(下面的示例)。我不明白參數化構造。文檔爲here,但他們沒有幫助。它有什麼作用?DrScheme中的'parametrize'是做什麼的?

+0

爲什麼使用tinyurl.com?在使用完整網址時沒有嚴重的空間限制,縮略圖使鏈接看起來更加可疑。 – 2009-12-08 22:34:56

+1

鏈接已末尾括號,這使得他們無法正常工作瓦特/加價,如此使用 – Claudiu 2009-12-09 00:04:05

+0

吉米尼聖誕節,這些鏈接甚至不會與引文,在底部降價的工作作風。 – Chuck 2009-12-09 01:22:37

回答

13

parameterize用於具有被「動態作用域」值。你得到一個參數make-parameter。參數本身表現爲一個函數:在沒有輸入的情況下調用它,並獲得它的值,用一個值調用它並設置該值。例如:

> (define p (make-parameter "blah")) 
> (p) 
"blah" 
> (p "meh") 
> (p) 
"meh" 

許多函數(包括許多基本函數)使用參數作爲自定義其行爲的一種方式。例如,printf將使用current-output-port參數值的端口打印內容。現在,假設你有一些功能,打印的東西:

> (define (foo x) (printf "the value of x is ~s\n")) 

通常你調用這個函數,看到印在屏幕上的東西 - 但在某些情況下,你想用它來打印一些文件或任何。你可以這樣做:

(define (bar) 
    (let ([old-stdout (current-output-port)]) 
    (current-output-port my-own-port) 
    (foo some-value) 
    (current-output-port old-stdout))) 

這樣做的一個問題是它很繁瑣 - 但這很容易用宏解決。 (實際上,PLT仍然有一個在某些語言中使用的構造:fluid-let)。但是這裏存在更多問題:如果調用foo會導致運行時錯誤,會發生什麼情況?這可能會導致系統處於不良狀態,所有輸出都會傳送到您的端口(並且您甚至不會看到問題,因爲它不會打印任何內容)。用於該溶液(其中fluid-let使用過)是保護儲蓄/與dynamic-wind參數的恢復,這可以確保如果有錯誤(多,如果你知道的延續),則該值仍然恢復。

所以,問題是什麼是有參數,而不是僅僅使用全局和fluid-let點?還有兩個問題是你無法用全局變量解決的。一種是當你有多個線程時會發生什麼 - 在這種情況下,臨時設置該值會影響其他線程,這些線程可能仍然要打印到標準輸出。參數通過每個線程具有特定值來解決這個問題。會發生什麼情況是,每個線程都從創建它的線程「繼承」該值,並且一個線程中的更改僅在該線程中可見。

另一個問題更爲微妙。說你有一個數值的參數,並且要做到以下幾點:

(define (foo) 
    (parameterize ([p ...whatever...]) 
    (foo))) 

在計劃,「尾調用」是很重要的 - 他們是創造循環和更多的基本工具。 parameterize做了一些神奇的事情,允許它暫時改變參數值,但仍保留這些尾部調用。例如,在上述情況下,你得到一個無限循環,而不是得到一個堆棧溢出錯誤 - 什麼情況是,當有不再需要做一個較早parameterize這些parameterize表達式可以以某種方式檢測其清理。

最後,parameterize實際上使用PLT的兩個重要部分來完成它的工作:它使用線程單元來實現每個線程的值,並且它使用連續標記來保存尾部調用。這些功能本身都很有用。

+0

真棒答案 - 謝謝! – Claudiu 2009-12-09 17:17:21

3

parameterize設定特定參數,以用於所述塊的持續時間指定的值,在不影響其外部它們的值。

+0

嗯有趣 – Claudiu 2009-12-09 00:04:46

3

參數化是通過它可以動態地重新綁定的現有函數內的值,而無需使用lambda這樣做的裝置。在實踐中,有時使用參數化來重新綁定函數中的值比使用lambda來傳遞參數和綁定參數要容易得多。

例如,假設你使用一個庫發出HTML到標準輸出,但爲方便起見,你要拍攝價值爲字符串,並在其上執行進一步的操作。庫設計人員至少有兩種選擇可以讓您輕鬆實現:1)接受輸出端口作爲函數的參數或2)參數化當前輸出端口值。 1是醜陋和麻煩。 2是更好的,因爲最可能的行爲是打印到標準輸出,但是如果你想打印到一個字符串端口,你可以參數化該函數的調用。