在没有 运行 函数的情况下检查 Clojure 前置条件?

Checking Clojure pre-conditions without running the function?

我有一个函数可以完成一些(可能很长的)工作 (defn workwork [x] ...) 和一些其他函数可以提前检查调用是否成功 (defn workwork-precondition-1 [x] ...)

每次调用 workwork(例如使用 :pre)时,都应评估前置条件函数。前置条件函数也应该收集(和:ed)在一个函数中,并直接提供给客户端代码(例如禁用按钮)。

在 Clojure 中解决这个问题同时避免代码重复的惯用方法是什么?

特别是,有没有什么方法可以在没有 运行 函数体的情况下评估函数的前置条件?

您可以将前提条件收集到一个函数中:

(defn foo-pre [x]
  (even? x))

然后在:pre风格的前置条件中调用函数:

(defn foo [x]
  {:pre [(foo-pre x)]}
  …)

对于使用 defn 引入的函数,您可以从 Var 上的元数据中提取 :pre 风格的前提条件:

(-> #'foo meta :arglists first meta)
;= {:pre [(foo-pre x)]}

对于任何其他参数的 :arglists 条目也是如此。

这里有两个注意事项:

  1. Var 元数据中自动生成的 :arglists 条目可能被覆盖。覆盖 :arglists 会导致上述有用的自动生成的元数据被丢弃。

  2. 上述(-> #'foo meta …)表达式返回的{:pre [(foo-pre x)]}值包含foo-pre作为文字符号 – 它'你有责任弄清楚它在 foo 的定义点指的是哪个函数。 (这可能会也可能不会——例如 foo 可以在顶级 letletfn 形式中 defn,其中 foo-pre局部函数。)

最后,匿名函数可能会使用 :pre:post,但目前还没有从函数本身中提取它们的机制。

要在没有 运行 函数体的情况下计算函数前提条件,您可以使用 robert-hookehttps://github.com/technomancy/robert-hooke/


    (use 'robert.hooke)

    (defn workwork [x] ...)

    (defn workwork-precondition-1 
      [f x]
      (if (precondition-1-satisfied? x)
        (f x)
        :precondition-1-not-satisfied))

    (add-hook #'workwork #'workwork-precondition-1)