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

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

0 投票
h2. 问题

动机问题是在 {{test.check}} 中实现 {{gen/let}}(另见 TCHECK-98)。

{{gen/let}} 的常见用法可能看起来像这样


(gen/let [a gen-a
          b gen-b]
  (f a b))


此代码的关键特征是 {{b}} 的生成器不依赖于 {{a}} 的值(尽管在一般情况下可能)。由于这种独立性,理想的展开是


(gen/fmap
  (fn [[a b]] (f a b))
  (gen/tuple gen-a gen-b))


然而,由于 {{gen/let}} 通常无法判断 {{b}} 的生成器表达式是否依赖于 {{a}},它需要回退到一个更通用的展开


(gen/fmap
  (fn [[a b]] (f a b))
  (gen/bind
    gen-a
    (fn [a]
      (gen/tuple (gen/return a) gen-b))))


使用 {{gen/bind}} 显着降低了缩小能力,因此最好在可能的情况下避免使用。

一个有知识的用户可以通过显式使用 {{gen/tuple}} 来解决这个问题,例如


(gen/let [[a b] (gen/tuple gen-a gen-b)]
  (f a b))


但我想大多数用户宁愿不必考虑这些事情。

h2. 可能的解决方案

h3. tools.analyzer

{{tools.analyzer}} 可能足够好,但对库来说是一个大的依赖项。

h3. tools.analyzer 的一个子集

Nicola 提到了提取分析器中某些子集的想法,这可能是最优选项。

h3. 一个用于宏展开宏体的机制

我相信,如果有一个稳健的机制可以让宏完全展开一个表达式,这个问题就会更容易({{clojure.core/macroexpand}} 和朋友有几个已知的错误)-- 通过扩展示式的简单 {{tree-seq}} 可以证明没有使用局部变量(虽然一种简单的方法可能错误地得出一个局部变量 **被** 使用,这可能是在 test.check 情况下可接受的妥协,而一个稳健的代码遍历器应该不困难地实现在扩展代码上)。

我相信 zach 的 [riddley|https://github.com/ztellman/riddley] 库做了一些类似的事情,依赖于 riddley 可能是非贡献库的最佳选择,但不是贡献库的可接受的依赖项。

1 个回答

0 投票
by
参考: https://clojure.atlassian.net/browse/CLJ-1997(由gfredericks报告)
...