> (define (f x) x)> (define (g x) (
letrec
((x x)) x))
> (define a
'(1 2 3))
> (f a)(1
23)> (eq? a (f a))
#t> (eq? a (g a))
#t> (define b (g a))
> (set-car! b 10)
> a(10
23)>
可見,g函式的定義中,named let並未深拷貝x的值,它只是建立傳入引數的引用而已.
那這也說明,如果乙個函式所有引數在遞迴過程中都會發生改變,那麼一般沒必要用named let.
又如:
;切割named let版 (1234) 2 -> (34)
(define (tail x n)
(let
recur ((x x)(n n))
(if (null
? x)
'()(if (> n 0
) (recur (cdr x) (- n 1))
(cons (car x) (recur (cdr x) (- n
1)))))))
;切割原始版
(define (tail x n)
(if (null
? x)
'()(if (> n 0
) (tail (cdr x) (- n 1))
(cons (car x) (tail (cdr x) (- n
1))))))
原始版就是更好的.
但是,對於遞迴過程中函式所有引數都在變化的情形,有兩種情況例外,仍然需要named let:
(1)函式要求返回遞迴過程中的某些變數的最終狀態.例如求乙個list的元素個數的函式定義:
(define (len x)(let recur ((x x)(y 0
)) (
if (null
? x)
y(recur (cdr x) (+ y
1)))))
由於需要乙個變數來記錄(cdr x)的次數,因此在內嵌函式recur中增加乙個引數y來實現是非常合適的.
(2)處理不定引數的情形.這個可以用map來作非常好的說明:
(define (imap f x . y)(if (null
? y)
(letrecur ((x x))
(if (null
? x)
'()
(cons (f (car x)) (recur (cdr x)))))
(letrecur ((x x) (y y))
(if (null
? x)
'()
顯然,結合條件判斷,named let能夠將複雜情形轉化為簡單情形.思路是:
如果y是空表,那麼imap等於乙個只有1個引數recur函式.否則就等於2個引數的recur函式.而後者的引數傳遞過程中,我們又需要用到1個引數的情形:
(imap car y)
(imap cdr y)這真是非常精妙的.
不應該,不應該
不應該在晚上喝一整瓶利咽的搞的反胃 不應該在吃大快活的時候點一杯奶茶的 不應該一天大腦都這麼緊張 有什麼辦法,都是自己找的 在天津累,天天加班。回到廣州上兩天班更累,連睡個覺6小時都保證不了。發現現在很容易失眠,因為大腦想事情太多了,又回到了n年前在大學又做專案又參加比賽的時候了。問題是以前我睡不著...
Go goroutine 不可濫用
goroutine 是go語言最大的創新,但這並不意味著我們可以隨意使用。原因 1 goroutine的指標傳遞是不安全的 2 goroutine增加了函式的危險係數 3 goroutine的濫用陷阱 處理方法 1 當啟動乙個goroutine的時候,如果乙個函式必須要傳遞乙個指標,但是函式層級很深...
請不要濫用異常
exception php的異常機制的功能非常強大,並且是可以跨作用域的傳遞豐富的資訊,但它強大的功能很容易讓我們濫用它。比如在使用者檢查登入時,如果密碼不正確,你可能會在模型中丟擲乙個異常,在控制器處理它。對於程式設計師,這樣做會很舒服,因為你不再費心思考慮心如何構建返回值和制定返回規範,也不必關...