Ausführen einer dynamisch gebundenen Funktion in Clojure

Ich möchte eine Reihe von Funktionsaufrufen in einer Datenstruktur speichern und später in einer anderen Funktion auswerten / ausführen.

Dies funktioniert wie geplant für Funktionen, die auf Namespace-Ebene mit @ definiert wurdedefn (obwohl die Funktionsdefinition nach dem Erstellen der Datenstruktur erstellt wurde), funktioniert aber nicht mit Funktionen, die durch @ definiert sinlet [name (fn oderletfn innerhalb der Funktion.

Hier ist mein kleines Beispiel:

(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
)))

Wenn Sie sich über meinen Testaufbau wundern, um das Ergebnis dieser 6 Anweisungen zu sehen, kommentiere / entkommentiere ich spezifisch die OK- / fehlerhaften Zeilen und rufe dann @ au(runit) von der REPL.

Gibt es eine einfache Lösung, die ich übernehmen könnte, um @ zu bekommeeval 'dquoted ruft Funktionen auf, um für Funktionen zu arbeiten, die in einer anderen Funktion definiert sind?

Aktualisieren

Dies (basierend auf dem Vorschlag von danlei) does Arbeit. Mal sehen, ob ich diese Methode im "echten Leben" zum Laufen bringen kann!

(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!
))

Aktualisieren

Dieser Code geht in meine Lösung für ein Einschränkung Zufriedenheit Problem - Ich will herausfinden Wem gehört das Zebra! Ich bin ziemlich neu in Clojure und insbesondere in der funktionalen Programmierung, und dies hat die Übung ziemlich herausfordernd gemacht. Ich falle in viele Gruben, aber ich bin damit einverstanden, da es Teil der Lernerfahrung ist.

Ich habe die Bedingungen als eine Reihe einfacher Vektoren angegeben, wie folgt:

[:con-eq :spain :dog]
[:abs-pos :norway 1]
[:con-eq :kools :yellow]
[:next-to :chesterfields :fox]

wobei der erste jedes Vektors die Art der Einschränkung angibt. Das führte jedoch zu einer umständlichen Implementierung eines Versandmechanismus für diese Regeln, sodass ich mich entschied, sie stattdessen als (zitierte) Funktionsaufrufe zu codieren:

'(coloc :japan :parliament) ; 10
'(coloc :coffee :green) ; 12
'(next-to :chesterfield :fox) ; 5

so kann ich die Einschränkungsregel mit einem einfachen @ versendeval. Dies scheint viel eleganter und "lispy". Für jede dieser Funktionen muss jedoch auf meine Domänendaten zugegriffen werden (mit dem Namenvars), und diese Daten ändern sich ständig, während das Programm ausgeführt wird. Ich wollte meine Regeln nicht durch ein zusätzliches Argument verfälschen, also wollte ichvars, um dem @ zur Verfügung zu steheval würde über dynamisches Scoping funktionieren.

Ich habe jetzt gelernt, dass dynamisches Scoping mit @ durchgeführt werden kanbinding, aber es braucht auch eindeclare.

Antworten auf die Frage(2)

Ihre Antwort auf die Frage