我定義了一個函數,它帶有兩個參數 - map和一個鍵。關鍵是從地圖參數分解defn vs讓我們分解
(defn myfunc [{v k} k]
v)
引用當我打電話:
(myfunc {:a 10} :a)
令人驚訝地產生預期的結果:10
類似的事情在咱們:
(let [{v k} {:a 10} k :a] v)
失敗,因爲k未定義在當第一部分被評估時。
我的問題是:爲什麼函數參數分解的行爲與的分解行爲不同,讓表達式?
我定義了一個函數,它帶有兩個參數 - map和一個鍵。關鍵是從地圖參數分解defn vs讓我們分解
(defn myfunc [{v k} k]
v)
引用當我打電話:
(myfunc {:a 10} :a)
令人驚訝地產生預期的結果:10
類似的事情在咱們:
(let [{v k} {:a 10} k :a] v)
失敗,因爲k未定義在當第一部分被評估時。
我的問題是:爲什麼函數參數分解的行爲與的分解行爲不同,讓表達式?
Macroexpanding的defn
形式我得到的這個等價(除去.withMeta的東西,並重新格式化):
(def myfunc
(fn* myfunc
([p__11393 k]
(let* [map__11394 p__11393
map__11394 (if (seq? map__11394)
(apply hash-map map__11394)
map__11394)
v (get map__11394 k)]
v))))
所以在這裏我們可以看到,{v k}
地圖其實首先分配給一個局部變量p__11393
。然後,if
語句測試該變量是否實際上是一個序列,如果是,則將其轉換爲哈希映射,否則保持原樣。重要的是,分配給k
的值在之後在地圖中查找,因此這種工作沒有錯誤(並且如果:a
不在地圖中,get
在那種情況下返回nil
也會如此)。
在另一方面macroexpanding的let
形式,我得到
(let*
[map__11431
{:a 10}
map__11431
(if (seq? map__11431) (apply hash-map map__11431) map__11431)
v
(get map__11431 k)
k
:a]
v)
,在這裏我們可以看到,v
得到的(get map__11431 k)
的結果,但k
沒有在這一點上還沒有定義,因此錯誤。
這不是一個完整的答案,但下面不工作:
user=> (defn myfunc [{v k} k] v)
#'user/myfunc
user=> (myfunc {:a 10} :a)
10
user=> (let [k :a {v k} {:a 10}] v)
10
user=>
這當然會起作用,因爲* k * – aav
現在的問題是,如果這樣的差異已經被認爲是一個錯誤或功能... – aav
我要說如果有人知道解構發生在函數體內,這並不奇怪,因此不是一個錯誤。但我認爲這個事實應該在適當的地方解釋得更好 - 例如,如果我沒有記錯的話,Clojure的喜悅就沒有真正理解這一點。 – Paul
什麼是有趣的(但並不令人驚訝),他不會工作:(defn myfunc [{v k} {k:k1}] v) – aav