defn与let关于分解

aav*_*aav 5 clojure

我定义了一个函数,它接受两个参数 - map和key.密钥是从map参数分解引用的

(defn myfunc [{v k} k]
   v)
Run Code Online (Sandbox Code Playgroud)

我打电话的时候:

  (myfunc {:a 10} :a)
Run Code Online (Sandbox Code Playgroud)

令人惊讶的是它产生了预期的结果:10

类似的东西:

(let [{v k} {:a 10} k :a] v)
Run Code Online (Sandbox Code Playgroud)

失败,因为此时没有定义k,当评估第一部分时.

我的问题是:为什么与let表达式中的分解相比,函数参数内部的分解行为有所不同?

Pau*_*aul 3

宏扩展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))))
Run Code Online (Sandbox Code Playgroud)

所以在这里我们可以看到映射{v k}实际上首先被分配给一个局部变量p__11393。然后该if语句测试该变量是否实际上是一个序列,如果是,则将其转换为哈希映射,否则保持原样。重要的是,在所有这些发生之后,分配给的值k会在映射中查找,因此它不会出现错误(并且如果不在映射中,也会在这种情况下返回)。:agetnil

另一方面,宏观扩展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)
Run Code Online (Sandbox Code Playgroud)

在这里我们可以看到v得到 的结果(get map__11431 k),但k此时尚未定义,因此出现错误。