2024年Clojure状态调查中分享您的想法!

欢迎!请参阅关于页面以获取更多关于如何工作的信息。

0

clojure.core/binding的文档字符串说它“以隐式do的形式执行exprs”。因此,我预期body的元素将按顺序执行,并返回最后一个的值(参见图例do的文档字符串)。

然而,body表达式并没有被包裹在dolet中,而是一个try。这允许有一些出人意料的行为

(binding [clojure.core/*print-length* 10]
  (/ 10 0)
  (catch Exception e
    :failure))

上述表达式返回:failure,而以下更明显地抛出编译器异常,因为如果没有try则不能使用catch

(binding [clojure.core/*print-length* 10]
  (do 
    (/ 10 0)
    (catch Exception e
      :failure)))

据我所知,从git历史来看,这个实现细节自2008年以来没有改变,所以可能有一些很好的理由。如果有,那是什么?如果没有,我们能修改binding的实现,使其真正地将do放在~@body周围吗?

1个答案

+2

被选择
 
最佳答案

try内有一个隐式的do - 你想要做什么却不起作用?

(binding []
  (println "1")
  (println "2")
  3)
;; 1
;; 2
;;=> 3
"你想要做什么会不起作用? "这是一个问题,回答是“没有”。 相反,有一件东西是起作用的(我在原始问题中的第一个代码块),我预计它会失败。
嗯,不要这么做。
(当我说的“起作用”的意思是它返回一个值,而不是抛出异常)
我想它必须要使用 try/finally,这样才能在包裹的代码无论成功或失败的情况下弹出绑定?
@Sean Corfield
对的,但它可以在主体周围加一个额外的 `do` 以防止调用者附加额外的 `catch` 子句到 `try` 的末尾。

@Alex Miller
显然,我永远不会故意这么做。 :)

所以我再看了一些资料,意识到你说得对。`binding` 期望其体是一个“expr(ession)s”列表。根据https://clojure.org/reference/evaluation, 除了特殊形式外,每个形式都是一个表达式。“(catch Exception e)”是一个特殊形式,因此它不一定是一个表达式。因此它不一定是 `binding` 的有效输入。看起来 `binding` 可以修改以处理这种输入而不使文档字符串无效,但当前的文档字符串与当前的行为相匹配,这正是我真正担心的。
...