I'd like to pre-store a bunch of function calls in a data structure and later evaluate/execute them from within another function.
This works as planned for functions defined at namespace level with defn
(even though the function definition comes after my creation of the data structure) but will not work with functions defined by let [name (fn
or letfn
inside the function.
Here's my small self-contained example:
(def todoA '(funcA))
(def todoB '(funcB))
(def todoC '(funcC))
(def todoD '(funcD)) ; unused
(defn funcA [] (println "hello funcA!"))
(declare funcB funcC)
(defn runit []
(let [funcB (fn [] (println "hello funcB"))]
(letfn [(funcC [] (println "hello funcC!"))]
(funcA) ; OK
(eval todoA) ; OK
(funcB) ; OK
(eval todoB) ; "Unable to resolve symbol: funcB in this context" at line 2
(funcC) ; OK
(eval todoC) ; "Unable to resolve symbol: funcC in this context" at line 3
)))
In case you're wondering about my test setup, to see the result of those 6 statements I comment/uncomment specific of the OK/failing lines and then call (runit)
from the REPL.
Is there a simple fix I could undertake to get eval
'd quote
d calls to functions to work for functions defined inside another function?
Update:
This (based on danlei's suggestion) does work. Let's see if I can get this method working in "real life!"
(def todoB '(funcB))
(declare funcB)
(defn runit []
(binding [funcB (fn [] (println "hello funcB"))]
(funcB)
(eval todoB) ; "Unable to resolve symbol: funcB in this context" at line 1!
))
Update:
This code is going into my solution for a Constraint Satisfaction Problem - I want to find out who owns the zebra! I'm fairly new to Clojure and especially functional programming, and this has made the exercise quite challenging. I'm falling into a lot of pits but I'm OK with that as it's part of the learning experience.
I used to specify the constraints as a bunch of simple vectors, like this:
[:con-eq :spain :dog]
[:abs-pos :norway 1]
[:con-eq :kools :yellow]
[:next-to :chesterfields :fox]
where the first of each vector would specify the kind of constraint. But that led me to an awkward implementation of a dispatch mechanism for those rules, so I decided to encode them as (quoted) function calls instead:
'(coloc :japan :parliament) ; 10
'(coloc :coffee :green) ; 12
'(next-to :chesterfield :fox) ; 5
so I can dispatch the constraining rule with a simple eval
. This seems a lot more elegant and "lisp-y." However, each of these functions needs to access my domain data (named vars
), and this data keeps changing as the program runs. I didn't want to blemish my rules by introducing an extra argument, so I wanted vars
to be available to the eval
'd functions via dynamic scoping.
I've now learned that dynamic scoping can be done using binding
, but it also needs a declare
.