簡單的讓巨集

方案中的 let 表示式實際上是巨集。他們可以用 lambdas 表達。一個簡單的 let 可能看起來像這樣:

(let ((x 1) (y 2))
  (+ x y))

當返回 let 體的最後一個表示式的值時,它將返回 3。如你所見,let-expression 實際上正在執行某些操作。如果我們用 lambdas 翻譯這部分程式碼,我們會得到這樣的結果:

((lambda (x y) (+ x y)) 1 2)

在這裡我們可以看到我們直接用 1 和 2 呼叫匿名 lambda。所以在這種情況下的結果也是 3。

考慮到這一點,我們理解 let 表示式由兩部分組成。它有引數和像 lambda 一樣的體,但區別在於,在評估後立即呼叫表示式。

為了解釋 let 表示式如何從抽象到具體的檢視,它看起來像這樣。

(let params body ...)
(let (param1 param2 ...) body ...)
(let ((p1 val1) (p2 val2) ...) body ...)

引數是在 let 的主體中使用的一對 (name value) 的列表。

為何使用 let 表示式?

讓表示式在方法中儲存變數特別有用,就像在類似語言中初始化變數一樣。使用 define 是有利的,因為在 let 表示式之外,變數已經消失了……使用 define 實際上是在當前執行環境中新增一個變數。無法刪除新增到全域性環境的變數。讓表達在任何地方都可以安全使用。它也可以用於重影變數而不觸及父範圍。

例如:

(let ((x 1))
  (let ((x 2) (y x))
    (display x)
    (display y))
  (display x))

它將列印:

2
1
1

在這種情況下,x 定義為 1,然後由第二個 let 中的 x 重影,值為 2。變數 y 以父範圍的值 x 啟動。執行內部 let 表示式後,它會顯示 x 的初始值為 1.內部 let 表示式不會更改父範圍的值。

每當你需要初始化變數時,你應該使用這樣的 let 表示式:

(let (
  (user (get-current-user session))
  (db (get-current-db session))
  (ids (get-active-ids session))
  )
  (mark-task-completed db user ids)
  (change-last-logged db user)
  (db-commit db))

在這個例子中,變數被初始化並在程式碼塊中多次使用。當 let 表示式完成時,變數會自動釋放,因為它們不再是必需的。