define
全球
首先,頂層程序由實現方式的不同部分中比在函數處理並且限定已定義的變量是不允許的。
(define a 10)
(define a 20) ; ERROR: duplicate definition for identifier
它可能發生在REPL中,因爲通常重新定義東西,但是在運行程序時這是絕對禁止的。在R5RS中,發生的事情之前沒有詳細說明,也沒有關注,因爲違反規範,它不再是計劃程序,實施者可以自由地做任何他們想做的事情。結果當然是很多未指定的東西獲得了不可移植或不穩定的實現特定行爲。
解決方案:
set!
變異綁定:
(define a 10)
(set! a 20)
define
在一個lambda(功能,讓...)
一個define
在拉姆達是完全不同的東西,由完全不同的部分實施處理。它是由宏/特殊形式lambda
使得它改寫爲letrec*
一個letrec*
或letrec
用於製造功能遞歸所以名稱必須是可在表達式的計算時間處理。正因爲如此,當你作爲參數傳遞時,它已經隱藏了n
。另外,從R6RS開始,實現者需要在綁定評估尚未初始化時發出錯誤信號,這可能會發生。之前R6RS實施者可以自由地做任何他們想要的東西:
(define (func n)
(define n (+ n 1)) ; illegal since n hasn't got a value yet!
n)
這實際上就變成了:
(define func
(lambda (n)
(let ((n 'undefined-blow-up-if-evaluated))
(let ((tmpn (+ n 1)))
(set! n tmpn))
n)))
現在,編譯器可能會看到它違反了在編譯時的規範,但許多實現不知道在它運行之前。
(func 5) ; ==> 42
如果實施者在書本上有良好的品味,完美的結果在R5RS。 在版本的區別,你說的作品是,這並不違反前身體評估n
的規則:
(define (func n)
(define n 5)
n)
變爲:
(define func
(lambda (n)
(let ((n 'undefined-blow-up-if-evaluated))
(let ((tmpn 5)) ; n is never evaluated here!
(set! n tmpn))
n)))
解決方案
使用非相沖突的名稱
(define (func n)
(define new-n (+ n 1))
new-n)
使用let
。當表達式得到評估時,它沒有自己的綁定:
(define (func n)
(let ((n (+ n 1)))
n))