2
votes

I'm trying to write a function which takes a sequence of bindings and an expression and returns the result.

The sequence of bindings are formatted thus: ([:bind-type [bind-vec] ... ) where bind-type is either let or letfn. For example:

([:let [a 10 b 20]] [:letfn [(foo [x] (inc x))]] ... )

And the expression just a regular Clojure expression e.g. (foo (+ a b)) so together this example pair of inputs would yeild 31.

Currently I have this:

(defn wrap-bindings
  [[[bind-type bind-vec :as binding] & rest] expr]
  (if binding
    (let [bind-op (case bind-type :let 'let* :letfn 'letfn*)]
      `(~bind-op ~bind-vec ~(wrap-bindings rest expr)))
    expr))

(defn eval-with-bindings
  ([bindings expr]
   (eval (wrap-bindings bindings expr))))

I am not very experienced with Clojure and have been told that use of eval is generally bad practice. I do not believe that I can write this as a macro since the bindings and expression may only be given at run-time, so what I am asking is: is there a more idiomatic way of doing this?

1
Is this purely as an exercise? I can't see this being at all useful in the real world. - Carcigenicate
"the bindings and expression may only be given at run-time" but why not just write Clojure and load that at runtime? This question seems like you might be reaching to unnecessarily reinvent a subset of Clojure. - Taylor Wood

1 Answers

2
votes

eval is almost always not the answer though sometimes rare things happen. In this case you meet the criteria because:

since the bindings and expression may only be given at run-time

  • You desire arbitrary code to be input and run while the program is going
  • The binding forms to be used can take any data as it's input, even data from elsewhere in the program

So your existing example using eval is appropriate given the contraints of the question at least as I'm understanding it. Perhaps there is room to change the requirements to allow the expressions to be defined in advance and remove the need for eval, though if not then i'd suggest using what you have.