Проверка анонимных функций, переданных в мою функцию во время выполнения, со спецификацией 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,

Другие вопросы по тегам