Clojure:如何避免对 map 获取中未找到的表达式进行评估

标签 clojure

我有一张名为机器人的 map 。在查找 map 时,如果给定键的机器人不存在,我想创建一个。 clojure.core/getnot-found arg 似乎正是我所需要的。

但是,似乎 not-found 表达式是急切求值的。如何防止这种评估,以便仅在机器人不存在时才创建一个新机器人?

robot> (def robots {1 {:name "R2D2"}})
#'robot/robots


robot> (get robots 1)
{:name "R2D2"}

robot> (get robots 1 (println "damn it"))
damn it
{:name "R2D2"}

最佳答案

问题是这不是一个分支语句——它实际上需要在 not-found 槽中得到一个值,而不是一个形式或函数。所以你可以使用分支语句:

(if-let [r (get robots 1)] r (println "Beep boop"))

如果打字太多,你可以考虑一下:

(defmacro get-lazy
  [map idx statement]
  `(if-let [v# (get ~map ~idx)] v# ~statement))

user=> (get-lazy robots 1 (println "Oops!"))
{:name "R2D2"}

根据 A.Webb 的评论提示,我们得出以下宏。它使用与上面相同的方法,并且还可以处理包含 falsenil 值的映射。它也比在 map 上调用 contains?get 更快。不要使用错误的返回值 (false/nil) 来提示您该项目不存在,而是使用 get 的内置功能并检查“中永远不会出现的内容”狂野” map 。

(defmacro get-lazy
 [map idx statement]
 `(let [r# (get ~map ~idx ~::nil)]
    (if (identical? r# ~::nil) ~statement r#)))

user=> (get-lazy {:idx 8} :idx (println "Yo."))
8
user=> (get-lazy {:coconuts :migration} :swallow (println "Who goes there?"))
Who goes there?
user=> (ns another.ns)
another.ns=> (user/get-lazy {:LUE ::nil} :LUE (println "42."))
:another.ns/nil

您可以避开宏并走功能路线:

(let [sentinel ::nil]
  (defn lazyget
   [map idx function]
   (let [r (get map idx sentinel)]
      (if (identical? r sentinel) (function) r))))

这在我的机器上有点慢。

关于Clojure:如何避免对 map 获取中未找到的表达式进行评估,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23197520/

相关文章:

Clojure 集 vs 不同 vs 重复数据删除?

clojure - 在 Clojure 中使用管道/流

Haskell 函数到 Clojure 函数的转换

java - 如何将目录添加到 Clojure 的类路径?

mysql - clostache/render 函数中是否有多个参数?

java - 在原始数组上调用 amap 时 Clojure 失败

list - 我可以将 "transpose"映射列表转换为 Clojure 中的列表映射吗?

java - 文本编辑器的 Clojure zipper 结构(带有映射和数组)

clojure - 获取使用 Clojure 的读取字符串读取的字符串的 "unread"部分

unit-testing - 如何在测试套件中包含clojure.spec的功能