Я хотел бы предварительно сохранить набор вызовов функции в структуре данных и позже оценить/выполнить их из другой функции.
Это работает как запланировано на функции, определяемые при уровне пространства имен с 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 звонит в функции для работы на функции, определяемые в другой функции?
Обновление:
Это (на основе предложения danlei) действительно работает. Давайте посмотрим, могу ли я получить этот метод, работающий в "реальной жизни!"
(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
. Это кажется намного более изящным и "шепелявость-y". Однако каждая из этих функций должна получить доступ к моим доменным данным (названный vars
), и эти данные продолжают изменяться как прогоны программы. Я не хотел портить свои правила путем представления дополнительного аргумента, таким образом, я хотел vars
быть доступным eval
'd функционирует через динамический обзор.
Я теперь узнал, что динамический обзор может быть сделан с помощью binding
, но этому также нужен a declare
.
Вы имеете в виду что-то вроде этого?
(def foo '(bar))
(declare bar)
(binding [bar (fn [] (println "hello bar"))]
(eval foo))
Если да, ваша проблема сводится к следующему:
(let [foo 1]
(eval 'foo))
Это не сработает, потому что eval не оценивать в лексической среде. Вы можете обойти это, используя vars:
(declare foo)
(binding [foo 1]
(eval 'foo))
Что касается этого, Clojure, похоже, имеет семантику, аналогичную CL, ср. the CLHS :
Оценивает форму в текущей динамической среде и нулевой лексической среде.
Я думаю, вы решаете не ту задачу. В функциональных языках функции являются значениями и могут быть назначены всему, что может хранить любое другое значение, например карта. Вы не должны пытаться манипулировать пространствами имен или исключать что-либо - это не Perl.
Попробуйте что-то вроде этого и используйте assoc для локального изменения карты:
user=> (def fnmap {:funcA (fn [x] (inc x)), :funcB (fn [x] (* x 2))})
#'user/fnmap
user=> ((:funcA fnmap) 10)
11
user=> ((:funcB fnmap) 10)
20