2

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?

2 Answers 2

6

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:

  1. 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.

  2. The {:pre [(foo-pre x)]} value returned by the above (-> #'foo meta …) expression contains foo-pre as a literal symbol – it'd be your responsibility to figure out which function it referred to at foo's point of definition. (This may or may not be possible – for example foo could be defn'd inside a top-level let or letfn form, with foo-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.

Sign up to request clarification or add additional context in comments.

Comments

0

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)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.