Я бы предпочел, чтобы примеры были в варианте Lisp (бонусные баллы для Clojure или Scheme), поскольку это то, с чем я лучше всего знаком, но любой отзыв о DBC в функциональных языках, конечно, будет ценен для большего сообщества.
Вот очевидный способ:
(defn foo [action options]
(when-not (#{"go-forward" "go-backward" "turn-right" "turn-left"} action)
(throw (IllegalArgumentException.
"unknown action")))
(when-not (and (:speed options) (> (:speed options) 0))
(throw (IllegalArgumentException.
"invalid speed")))
; finally we get to the meat of the logic)
Что мне не нравится в этой реализации, так это то, что логика контракта скрывает основные функции; истинное назначение функции теряется при условных проверках. Это та же проблема, которую я поднял в этом вопросе. В императивном языке, таком как Java, я могу использовать аннотации или метаданные / атрибуты, встроенные в документацию, чтобы вывести контракт из реализации метода.
Кто-нибудь смотрел на добавление контрактов к метаданным в Clojure? Как можно использовать функции высшего порядка? Какие еще есть варианты?