不應濫用named let

2022-04-28 22:51:20 字數 1660 閱讀 1234

> (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版 (123

4) 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的異常機制的功能非常強大,並且是可以跨作用域的傳遞豐富的資訊,但它強大的功能很容易讓我們濫用它。比如在使用者檢查登入時,如果密碼不正確,你可能會在模型中丟擲乙個異常,在控制器處理它。對於程式設計師,這樣做會很舒服,因為你不再費心思考慮心如何構建返回值和制定返回規範,也不必關...