0

I have an algorithm which uses a bunch of different functions or steps during it's work. I would like to run the algorithm with different possible functions bound to those steps. In essence I want to prepare some sets of values (which specific function should be bound to this specific step) and run my algorithm with every one of those sets. And to capture results of every run alongside with input set.

Something like that:

(binding [step1 f1
          step2 f2]
(do-my-job))

(binding [step1 f11
          step2 f22]
(do-my-job))

but with dynamic binding expressions.

What are my options?

4 Answers 4

2

So you are trying to do something like a parameter sweep?

I can't see why you need to do a dynamic binding. Your algorithm is defined in terms of first class function calls. Just pass the functions in as parameters to your algorithms.

To try all the values, just generate a permutation of the values, and run map over this list. You will get all the results from this.

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

2 Comments

I don't want to pass all required functions all the way down to the place, where it is needed.
Pass them as a single data structure, like a map. Your algorithm functions will all look similar then -- parameters carrying the data, and a single structure carrying all the functions you need.
1

because binding is a macro you will need to write a macro that generates the dynamic binding forms.

1 Comment

Can you may be point me to some reading on this topic? Have never written a macro :(
0

Well, it seems I have it working the following way:

(def conditions [[`step1 f1 `step2 f2] [`step1 f11 `step2 f22]])

(map #(eval `(binding ~% body)) conditions)

Comments

0

So, I have tested this and as far as I can see, it all just works.

In the example below, I create a var, then rebind this var to a function. As you can see the call to the function happens outside of the lexical scope of binding form, so we have dynamic binding here.

(def
  ^{:dynamic true}
  *bnd-fn*
  nil
  )

(defn fn1 []
  (println "fn1"))

(defn fn2 []
  (println "fn2"))


(defn callfn []
  (*bnd-fn*))

;; crash with NPE
(callfn)

;; prints fn1
(binding [*bnd-fn* fn1]
  (callfn))

;; prints fn2
(binding [*bnd-fn* fn2]
  (callfn))

I've been using a similar approach for a library of my own (Clojure-owl if you are interested!), although in my case the thing I with to dynamically rebind is a Java object.

In that case, while I have allowed dynamic rebinding, in most cases I don't; I just use a different java object for different name spaces. This works nicely for me.

In reply to your comment, if you want to have a single binding form, then, this is easy to achieve. Add the following code.

(defn dobinding [fn]
  (binding [*bnd-fn* fn]
    (callfn)))

(dorun
 (map dobinding
             [fn1 fn2]))

The function dobinding runs all of the others. Then I eval this with a single map (and dorun or you get a lazy sequence). This runs two functions for each step. Obviously, you will need to pass a list of lists in. You should be able to parallelize the whole lot if you choose.

This is a lot easier than trying to splice in the whole vector. The value in a binding form is evaluated so it can be anything you like.

4 Comments

Dynamic binding per se is simple. My question was about how to dynamically provide that vector that you pass to binding macro
Unless the number of steps you have is variable in itself -- that is you want to vary "step1" and "step2", then you don't need to do this. Varying step1 and step2 doesn't make sense because your algorithm is defined in these terms. It's just the values you need to vary. So, I still cannot see why you need to dynamically bind the whole vector -- just the values you are set predetermined symbols to. This is straight-forward.
Your solution, at least as I have understood it, requires, that if I want to test my algo with 5 different values for step1 and 5 different values for step2, then I have to write manually 25 binding statements. I would like to pass 2 seqs, and e.g. write 1 binding inside for.
I extended by answer to cope with this. You only need one binding form, inside a function, and you call it is often as you like with different values.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.