[英]How does clojure bind variable parameters?
我是 Clojure 的新手。問題出在我曾經檢查過conj
的源代碼時:
(def conj
(fn ^:static conj
([] [])
([coll] coll)
([coll x] (clojure.lang.RT/conj coll x));4
([coll x & xs] ;1
(if xs ;2
(recur (clojure.lang.RT/conj coll x) (first xs) (next xs)) ;3
(clojure.lang.RT/conj coll x)))))
conj
的源代碼顯示,它使用 recur 來實現該功能。 這個源代碼看起來很簡單。 我感到困惑的是它在確定遞歸是否需要繼續時使用的條件。 看起來它會檢查變量參數是否為nil
,但如果變量參數為nil
,它很快就相當於conj
的第三個“arity”? 然后我嘗試評估以下表達式:
user=> (conj [] 1 (next []))
[1 nil]
user=>
它正常工作並成功地將nil
添加到向量中。 我知道 clojure 實際上將nil
包裝在一個列表中並將其傳遞給函數,但我不明白為什么recur
可以傳遞一個真正的nil
? 為什么 clojure 會識別並匹配正確的“arity”?
user=> (def my_conj
(fn [coll x & xs]
(println "xs is" xs)
(if xs
(recur (clojure.lang.RT/conj coll x) (first xs) (next xs))
(clojure.lang.RT/conj coll x))))
#'user/my_conj
user=> (my_conj [] 1 (next []))
xs is (nil)
xs is nil
[1 nil]
好的,我很抱歉沒有早點意識到您遇到了我以前從未見過的 Clojure 行為的一個方面。 今天我學到了一些關於 Clojure 的新知識,並在 10 年的時間里使用它,這讓我感到驚訝。
這在 Clojure 官方文檔的幾句話中提到了 recur,這里: https : //clojure.org/reference/special_forms#recur
這是一個社區編寫的示例和文檔(因此不是“官方”)頁面,它描述了具有可變參數的函數的 recur 行為: https : //clojuredocs.org/clojure.core/recur#example-55ff3cd4e4b08e404b6c1c7f
我建議復制此函數,將其名稱更改為其他名稱,並向println
添加一些您感興趣的值的調用,例如 x、xs 等,然后觀察在 Clojure REPL 會話中打印的內容使用您感興趣的不同參數調用您的函數。
該if xs
如果值為true xs
是比所有其他的任何值nil
或false
。 值(nil)
是一個元素的列表,當用作if
條件表達式時被認為是 true。
用參數聲明的函數部分[coll x & xs]
表示“將第一個參數的值綁定到coll,將第二個參數的值綁定到x,然后如果沒有更多參數,則將xs綁定到值nil ,否則將 xs 與作為剩余參數列表的值綁定”。
您可以使用這個根本不使用 recur 的更簡單的函數來看到這一點:
user=> (defn my-fn [a & xs]
(println "a=" a " xs=" xs))
user=> (my-fn 1)
a= 1 xs= nil
user=> (my-fn 1 2)
a= 1 xs= (2)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.