defn与let关于分解

时间:2011-10-17 16:39:04

标签: clojure

我定义了一个函数,它接受两个参数 - map和key。密钥从映射参数分解

引用
(defn myfunc [{v k} k]
   v)

我打电话的时候:

  (myfunc {:a 10} :a)

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

let中的类似内容:

(let [{v k} {:a 10} k :a] v)

失败,因为当评估第一部分时, k 目前尚未定义。

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

2 个答案:

答案 0 :(得分:3)

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不在map,get在这种情况下返回nil

另一方面,宏扩展我得到的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,因此错误。

答案 1 :(得分:0)

这不是一个完整的答案,但以下方法确实有效:

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=>