Я бы хотел предварительно сохранить несколько вызовов функций в структуре данных, а затем оценить / выполнить их из другой функции.
Это работает, как и планировалось, для функций, определенных на уровне пространства имен с defn
(хотя определение функции приходит после того, как я создал структуру данных), но не будет работать с функциями, определенными let [name (fn
или letfn
внутри функции.
Вот мой небольшой автономный пример:
(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
)))
В случае, если вам интересно узнать о моей настройке теста, чтобы увидеть результат этих 6 операторов, я комментирую / раскомментирую специфичные для OK / неудачные строки, а затем вызываю (runit)
из REPL.
Есть ли какое-то простое исправление, которое я мог бы предпринять, чтобы получить eval
'd quote
d вызовов функций для работы для функций, определенных внутри другой функции?
Обновление:
Это (по предложению Данлея) работает .Давайте посмотрим, смогу ли я заставить этот метод работать в «реальной жизни!»
(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!
))
Обновление:
Этот код входит в мое решение для Проблема удовлетворения ограничений - Я хочу выяснить , кому принадлежит зебра !Я довольно новичок в Clojure и особенно в функциональном программировании, и это сделало упражнение довольно сложным.Я попадаю во многие ямы, но с этим у меня все в порядке, поскольку это часть опыта обучения.
Я использовал для определения ограничений в виде набора простых векторов, например:
[:con-eq :spain :dog]
[:abs-pos :norway 1]
[:con-eq :kools :yellow]
[:next-to :chesterfields :fox]
, где первый из каждого вектора будет указывать вид ограничения.Но это привело меня к неловкой реализации механизма диспетчеризации этих правил, поэтому я решил вместо этого закодировать их как (цитируемые) вызовы функций:
'(coloc :japan :parliament) ; 10
'(coloc :coffee :green) ; 12
'(next-to :chesterfield :fox) ; 5
, чтобы я мог отправить ограничивающее правило с помощью простого eval
.Это выглядит намного более элегантно и «шутливо».Однако каждой из этих функций требуется доступ к данным моего домена (с именем vars
), и эти данные постоянно меняются по мере выполнения программы.Я не хотел портить свои правила, вводя дополнительный аргумент, поэтому я хотел, чтобы vars
был доступен для функций eval
d через динамическую область видимости.
Теперь я узнал, что динамическая область видимостиможно сделать с помощью binding
, но для этого также нужно declare
.