Проверка анонимных функций, переданных в мою функцию во время выполнения, со спецификацией clojure
Скажи у меня есть функция a
это берет функцию (fn
) в качестве аргумента:
(defn a [f] ....)
,
Для того, чтобы дать приятное сообщение об ошибке вызывающей стороне, я бы во время выполнения проверить fn
аргумент.
Возможно ли это, и как мне поступить? Могу ли я просто во время выполнения fdef
это, а затем инструмент после вызова, что-то вроде:
(defn a [f]
;;.... spec f here on the fly, and call f, throw exception if f
;; does not conform to spec
)
Это мудро или это имеет смысл с философской точки зрения?
1 ответ
Могу ли я просто во время выполнения fdef это, а затем инструмент после вызова [...]
Нет потому что instrument
принимает символ, разрешает его переменную и, по существу, заменяет его новой функцией, которая оборачивает оригинал - вот где выполняется работа по проверке входных аргументов. В вашем примере у вас не будет доступа к f
"оригинальный" символ функции, а анонимные функции не разрешаются в переменную.
Вы можете специфицировать функции высшего порядка, чтобы вы могли специфицировать a
как это:
(defn a [f] (f (rand-int)))
(s/fdef a :args (s/cat :f (s/fspec :args (s/cat :x number?))))
(st/instrument `a)
(a inc) ;; => 2
(a str) ;; => "1"
(a (fn [x] (assoc x :foo 'bar))) ;; spec error b/c fn doesn't conform
Но... учтите, что любая функция передается как f
для инструментальных a
будет вызываться несколько раз со случайными входами! Вот как спецификация определяет, соответствует ли функция.
(a #(doto % prn inc))
-1
-0.75
...
=> 0.18977464236944408
Очевидно, вы не захотите использовать это с побочными эффектами или дорогими функциями. Я бы только рекомендовал использовать instrument
для тестирования / разработки. Вы также можете использовать s/assert
в вашей функции, но это все равно будет вызывать f
многократно.
(s/def ::f (s/fspec :args (s/cat :x number?)))
(defn a [f]
(s/assert ::f f)
(f (rand)))
(s/check-asserts true)
Это мудро или это имеет смысл с философской точки зрения?
Это действительно зависит от характера вашей программы и возможной области функций, передаваемых как f
,