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

欢迎!请参阅关于页面以获取有关如何使用此站点的更多信息。

0
错误
以下是一个可以粘贴到repl中的实现。希望得到反馈


(defn ^{:private true} local-bindings
  "生成局部绑定名称到其值的映射."
  [env]
  (let [symbols (map key env)]
    (zipmap (map (fn [sym] `(quote ~sym)) symbols) symbols)))

(defmacro assert
  "评估expr,如果它不评估为
 逻辑真,则抛出异常."
  {:added "1.0"}
  [x]
  (when *assert*
    (let [bindings (local-bindings &env)]
      `(when-not ~x
         (let [sep# (System/getProperty "line.separator")]
           (throw (AssertionError. (apply str "断言失败: " (pr-str '~x) sep#
                                          (map (fn [[k# v#]] (str "\t" k# " : " v# sep#)) ~bindings)))))))))

15 个答案

0

评论由:importer制作

fogus说:哦,但是这整个失败了:((let (link: x 1 y 2 z 3 a 1 b 2 c 3) (assert (= (link: x y) (link: a c)))))). 所以也许,除非你真的想让它变得复杂,否则只打印所有局部变量会更好。
:f

0

评论由:importer制作

http://www.assembla.com/spaces/clojure/tickets/415转换而来

0

评论由:importer制作

Jira回答说:为了说明,我试了一个简单的例子

user=> (let [a 1 b 2] (assert (= a b)))

<由于编译异常 java.lang.AssertionError: 断言失败: (= a b)

a : 1
b : 2
`

0

评论由:importer制作

jawolfe说:参见以下链接中的评论

http://groups.google.com/group/clojure-dev/browse_frm/thread/68d49cd7eb4a4899/9afc6be4d3f8ae27?lnk=gst&q=assert#9afc6be4d3f8ae27

还有一些建议可以加入其中:除了/而不是打印局部变量,如何保存这些变量呢?例如,将变量 assert-bindings 绑定到局部变量映射中。这样就不会遇到无限/非常大的序列,并允许用户更详细地查询失败的值(尤其是在局部变量打印不透明时非常有用)。

0

评论由:importer制作

stuart.sierra说:另一种方法,我很愿意提供
http://github.com/stuartsierra/lazytest/blob/master/src/main/clojure/lazytest/expect.clj

0
_是由导入器发表的评论

Fogus说:当然,如果你做一些类似的事情会让人觉得奇怪
(let [x 1 y 2 z 3 a 1 b 2 c 3] (assert (= x y)))
java.lang.AssertionError: 断言失败: (= x y)
 x : 1
 y : 2
 z : 3
 a : 1
 b : 2
 c : 3
 (无源文件:0)
</code></pre>

所以也许可以稍作修改
<pre><code>(defmacro assert
  "评估表达式并在其结果不为逻辑真时抛出异常。"
  {:added "1.0"}
  [x]
  (when *assert*
    (let [bindings (local-bindings &env)]
      `(when-not ~x
         (let [sep#  (System/getProperty "line.separator")
               form# '~x]
           (throw (AssertionError. (apply str "断言失败:" (pr-str form#) sep#
                                          (map (fn [[k# v#]]
                                                    (when (some #{k#} form#)
                                                                                                           
                                               ~bindings)))))))
</code></pre>

因此,现在它只是
<pre><code>(let [x 1 y 2 z 3 a 1 b 2 c 3] (assert (= x y)))
java.lang.AssertionError: 断言失败: (= x y)
 x : 1
 y : 2
 (无源文件:0)

:f
0
评论由:jweiss_

关于 fogus 上次评论的一个小改动,我实际上在用它。你需要在使用 'some' 检查局部变量是否在形式中使用之前先将该引用形式展平

(defmacro assert
  "评估表达式并在其结果不为逻辑真时抛出异常。"
  {:added "1.0"}
  [x]
  (when *assert*
    (let [bindings (local-bindings &env)]
      `(when-not ~x
         (let [sep#  (System/getProperty "line.separator")
               form# '~x]
           (throw (AssertionError. (apply str "断言失败:" (pr-str form#) sep#
                                          (map (fn [[k# v#]]
                                                 (when (some #{k#} (flatten form#))
                                                                                                           
                                               ~bindings)))))))
0

评论由:stu

我暂时搁置此事,直到我们更多的关于 http://dev.clojure.org/display/design/Error Handling 的协议。例如,考虑到Clojure中抛出的所有异常都应提供访问局部变量的功能。

当我那不切实际的梦想破灭后,我会在下一次发布前再次审视这段代码。

0
评论由:stu_

当你可以指定一个回调时(见下文),为什么要尝试猜测某人打算如何处理局部变量(或其他任何上下文),这是有用的。上周,我有一个只在CI虚拟机中失败的断言,当时没有调试器可用。

Rich,冒着重复旧观点的风险,我仍然认为这是一个好主意。调试器并不总是可用,这是一个 Lisp 比 其他环境能提供更多信息的地方。如果您需要下面的代码补丁,请在此标记等待我,否则请拒绝此工单,以便我停止查看它。:-)



(def ^:dynamic *assert-handler* nil)

(defn ^{:private true} local-bindings
  "生成局部绑定名称到其值的映射."
  [env]
  (let [symbols (map key env)]
    (zipmap (map (fn [sym] `(quote ~sym)) symbols) symbols)))

(defmacro assert
  [x]
  (when *assert*
    (let [bindings (local-bindings &env)]
      `(when-not ~x
         (let [sep#  (System/getProperty "line.separator")
               form# '~x]
           (if *assert-handler*)
             (*assert-handler* form# ~bindings)
             (throw (AssertionError. (apply str "断言失败:" (pr-str form#) sep#
                                                                         
                                                                                                                        (当 (某些 #{k#} (压平 form#))
                                                                                                v# sep#)))
                                                 ~bindings))))))))))
0

评论者:jweiss

我对自己的版本代码做了一点点改进:压平操作不改变集合字面量。所以如果你做 (assert (某些 #{x} (link: a b c d))),x 的值将不会被打印。下面是修改过的压平操作

(defn symbols [sexp] "从表达式中返回只是符号,包括那些在字面量(集合、映射、列表、向量)中的符号。"(distinct (filter symbol? (tree-seq coll? seq sexp))))

0

评论者:jafingerhut

附上 Stuart Halloway 版本的此想法的 git 格式补丁 clj-415-assert-prints-locals-v1.txt。我没有提倡它优于其他变体,只是将文件附加到 JIRA 工单。

0

评论者:michaelblume

之前的补丁与 CLJ-1005 不兼容,CLJ-1005 将 zipmap 移至 clojure.core 的后期。我重写了以使用 into。

0

评论者:michaelblume

这两个补丁与 CLJ-1224 有某种不兼容性。在构建我的 compojure-api 项目时,我得到以下错误

`
主线程中的异常:java.lang.UnsupportedOperationException:无法为原生前端变量类型标注

at clojure.lang.Compiler.analyze(Compiler.java:6569)
       ...
at clojure.main.main(main.java:37)

原因:java.lang.UnsupportedOperationException:无法为原生前端变量类型标注

at clojure.lang.Compiler$LocalBindingExpr.<init>(Compiler.java:5792)
at clojure.lang.Compiler.analyzeSymbol(Compiler.java:6929)
at clojure.lang.Compiler.analyze(Compiler.java:6532)
... 299 more

失败。
`

0

评论者:jafingerhut

Michael,你是否发现这些补丁之间存在不兼容性,因为你想运行一个包含所有这些补丁的修改版Clojure?如果这样理解,那就是这样。

如果你在寻找相互不兼容的补丁对,我建议你有一个不同的爱好 :-) 它们平均每月有大约9次应用,所以应该有足够的时间来解决它们之间的不一致。

0
参考: https://clojure.atlassian.net/browse/CLJ-415 (由 alex+import 报告)
...