我有一个函数执行一些(可能很长的)工作(defn workwork [x] ...)
和其他一些函数来检查调用是否会提前成功(defn workwork-precondition-1 [x] ...)
。
每次调用workwork
时都应评估前置条件函数(例如,使用:pre
)。前置条件函数也应该在单个函数中收集(和编辑),并直接用于客户端代码(例如,禁用按钮)。
哪种方法可以在Clojure中解决这个问题,同时避免代码重复?
特别是,有没有办法在不运行函数体的情况下评估函数的前置条件?
答案 0 :(得分:4)
您可以将前置条件收集到函数中:
(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)]}
同样对于任何其他arities的:arglists
条目。
这里有两点需要注意:
可能会覆盖Var的元数据中自动生成的:arglists
条目。覆盖:arglists
会导致抛出上述类型的有用自动生成的元数据。
上述{:pre [(foo-pre x)]}
表达式返回的(-> #'foo meta …)
值包含foo-pre
作为文字符号 - 您有责任弄清楚它在foo
的定义点引用了哪个函数。 (这可能是也可能是不可能的 - 例如foo
可以defn
位于顶级let
或letfn
表单中,foo-pre
本地功能。)
最后,匿名函数可以使用:pre
和:post
,但目前没有从函数本身中提取它们的机制。
答案 1 :(得分:0)
在不运行函数体的情况下评估函数前置条件,可以使用robert-hooke
库https://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)