问题
I have one function that does some (possibly lengthy) work (defn workwork [x] ...)
and some other functions to check if the call will succeed ahead of time (defn workwork-precondition-1 [x] ...)
.
The precondition functions should be evaluated every time workwork
is called (e.g. using :pre
). The precondition functions should also be collected (and:ed) in a single function and made available to client code directly (e.g. to disable a button).
Which is the idiomatic way to solve this in Clojure while avoiding code duplication?
In particular, is there any way to evaluate the pre-conditions of a function without running the function body?
回答1:
You can just collect your preconditions into a function:
(defn foo-pre [x]
(even? x))
Then call the function in a :pre
-style precondition:
(defn foo [x]
{:pre [(foo-pre x)]}
…)
For functions introduced using defn
, you can extract the :pre
-style preconditions from the metadata on the Var:
(-> #'foo meta :arglists first meta)
;= {:pre [(foo-pre x)]}
And similarly for the :arglists
entries for any other arities.
There are two caveats here:
The automatically-generated
:arglists
entry in the Var's metadata maybe be overridden. Overriding:arglists
results in the above kind of useful automatically-generated metadata to be thrown out.The
{:pre [(foo-pre x)]}
value returned by the above(-> #'foo meta …)
expression containsfoo-pre
as a literal symbol – it'd be your responsibility to figure out which function it referred to atfoo
's point of definition. (This may or may not be possible – for examplefoo
could bedefn
'd inside a top-levellet
orletfn
form, withfoo-pre
a local function.)
And finally, anonymous functions may use :pre
and :post
, but there is currently no mechanism for extracting them from the function itself.
回答2:
to evaluate the function precondition without running the function body,you can use robert-hooke
library 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)
来源:https://stackoverflow.com/questions/29320127/checking-clojure-pre-conditions-without-running-the-function