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

欢迎!请参阅关于页面,了解更多关于这个功能的信息。

0
Clojure
以下宏展开的结果无法评估,抛出`java.lang.NegativeArraySizeException`


(macroexpand-1 '(case :a
                  (:a-36 :b-36) 36
                  (:a-37 :b-37) 37
                  (:a-38 :b-38) 38
                  (:a-39 :b-39) 39
                  (:a-40 :b-40) 40
                  (:a-42 :b-42) 42))

;; =>

(clojure.core/let
    [G__8112 :a]
  (case*
    G__8112
    0
    31
    (throw
      (java.lang.IllegalArgumentException.
        (clojure.core/str "No matching clause: " G__8112)))
    {3 [:b-36 36],
     4 [:b-37 37],
     6 [:b-40 40],
     13 [:b-39 39],
     14 [:b-38 38],
     18 [:a-42 42],
     20 [:a-40 40],
     21 [:a-38 38],
     22 [:a-37 37],
     24 [:a-39 39],
     27 [:b-42 42],
     28 [:a-36 36]}
    :compact
    :hash-identity
    nil))



如果您从上面的case中删除任何选项,则宏展开可以正确评估。

原因在于`case*`在REPL产生的`clojure.lang.PersistentArrayMap`上受阻,而产生的是`clojure.lang.PersistentTreeMap`类型。

结果是宏展开的列表不能在不显式检查映射的具体类型的情况下自由地操作。特别是,`clojure.walk/walk`将产生无法评估的结果。

原始问题:https://github.com/clojure-emacs/cider/issues/2335

5 回答

0
by
_评论由:jafingerhut_ 提供

我在 Ubuntu 16.04 Linux 系统上进行了尝试,运行 OpenJDK 11.0.1,Clojure 1.10.0,在 Leiningen REPL 中,也使用带这些命令行选项的 `clj` 工具运行来使用 Clojure 1.10.0

{{
clj -Sdeps "{:deps {org.clojure/clojure {:mvn/version \"1.10.0\"}}}"
}}
当我尝试评估这个表达式时

{{
(eval (macroexpand-1 '(case :a
                  (:a-36 :b-36) 36
                  (:a-37 :b-37) 37
                  (:a-38 :b-38) 38
                  (:a-39 :b-39) 39
                  (:a-40 :b-40) 40
                  (:a-42 :b-42) 42)))
}}
我没有得到一个 java.lang.NegativeArraySizeException。相反,我得到了与尝试评估 (case :a ...) 表达式(不使用 macroexpand-1 和 eval 调用)时相同的抛出异常,这是一个 IllegalArgumentException,因为这里期望有 "不匹配的子句::a"。

你能多说一点你正在做什么从而导致抛出 java.lang.NegativeArraySizeException 异常吗?
0
by

_评论由:jafingerhut_ 提供

我希望这个指向原始 Cider 问题的链接比上面那个更容易理解,上面的链接看起来像与其他 URL 拼接了:https://github.com/clojure-emacs/cider/issues/2335

我通常不使用 Cider,所以我对尝试在那里重现问题不太感兴趣,但如果是仅在 Cider 中才能重现,听起来问题可能就出在那里?

0
by

_评论由:admin_ 提供

我无法重现这个问题。在一个 Clojure 1.10.0 repl 中

user=> (case :a (:a-36 :b-36) 36 (:a-37 :b-37) 37 (:a-38 :b-38) 38 (:a-39 :b-39) 39 (:a-40 :b-40) 40 (:a-42 :b-42) 42) 运行时错误(IllegalArgumentException)在 user/eval145 (REPL:1)。不匹配的子句::a (eval (macroexpand-1 '(case :a (:a-36 :b-36) 36 (:a-37 :b-37) 37 (:a-38 :b-38) 38 (:a-39 :b-39) 39 (:a-40 :b-40) 40 (:a-42 :b-42) 42))) 运行时错误(IllegalArgumentException)在 user/eval150 (REPL:1)。不匹配的子句::a

我缺少什么?

0
by
_评论由:bronsa_ 提供

引发此问题的方法之一是手动复制宏展开的代码。这会迫使字面量被读取为一个普通的映射,而不仅仅是一个排序映射。


user=> (clojure.core/let
    [G__8112 :a]
  (case*
    G__8112
    0
    31
    (throw
      (java.lang.IllegalArgumentException.
        (clojure.core/str "No matching clause: " G__8112)))
    {3 [:b-36 36],
     4 [:b-37 37],
     6 [:b-40 40],
     13 [:b-39 39],
     14 [:b-38 38],
     18 [:a-42 42],
     20 [:a-40 40],
     21 [:a-38 38],
     22 [:a-37 37],
     24 [:a-39 39],
     27 [:b-42 42],
     28 [:a-36 36]}
    :compact
    :hash-identity
    nil))
Syntax error (NegativeArraySizeException) 编译错误 fn* at (REPL:1:1)。
null


我不会认为这是一个错误:`case*` 特殊形式的要求是映射必须排序,如果确实存在错误,它应该在源头,在任何负责递归和转换宏展开形式以及将排序映射转换为普通映射的代码中。

这在我过去曾多次受到影响,我建议(如附件中补丁所示)在第时间简单添加一个检查,如果映射没有排序则抛出异常。
0
参考:[https://clojure.atlassian.net/browse/CLJ-2511](https://clojure.atlassian.net/browse/CLJ-2511)(由 vitoshka 报告)
...