Это походит на хороший пример использования для многопоточности... Я думал бы, что Вы могли довольно легко установить один поток для чтения данных, в то время как другой (s) обрабатывают его. Это может быть способом существенно увеличить воспринятую производительность. Просто мысль.
Clojure уже поддерживает предварительные и последующие условия, к сожалению, не очень хорошо документированные:
Должен ли я использовать функцию или макрос для проверки аргументов в Clojure?
Я мог бы представить что-то подобное в Clojure:
(defmacro defnc
[& fntail]
`(let [logic# (fn ~@(next fntail))]
(defn ~(first fntail)
[& args#]
(let [metadata# (meta (var ~(first fntail)))]
(doseq [condition# (:preconditions metadata#)]
(apply condition# args#))
(let [result# (apply logic# args#)]
(doseq [condition# (:postconditions metadata#)]
(apply condition# result# args#))
result#)))))
(defmacro add-pre-condition!
[f condition]
`(do
(alter-meta! (var ~f) update-in [:preconditions] conj ~condition)
nil))
(defmacro add-post-condition!
[f condition]
`(do
(alter-meta! (var ~f) update-in [:postconditions] conj ~condition)
nil))
Пример сеанса:
user=> (defnc t [a test] (a test))
\#'user/t
user=> (t println "A Test")
A Test
nil
user=> (t 5 "A Test")
java.lang.ClassCastException: java.lang.Integer (NO_SOURCE_FILE:0)
user=> (add-pre-condition! t (fn [a _] (when-not (ifn? a) (throw (Exception. "Aaargh. Not IFn!")))))
nil
user=> (t 5 "A Test")
java.lang.Exception: Aaargh. Not IFn! (NO_SOURCE_FILE:0)
user=> (t println "A Test")
A Test
nil
Итак, вы могут определять функцию, а затем определять предварительные и последующие условия, где угодно, не загромождая логику самой функции.
функции условий должны генерировать исключение, если что-то не так.