Проверка предварительных условий Clojure без запуска функции?

У меня есть одна функция, которая выполняет некоторую (возможно, длительную) работу (defn workwork [x] ...), и несколько других функций, чтобы заранее проверить, будет ли вызов успешным (defn workwork-precondition-1 [x] ...).

Функции предварительных условий должны оцениваться каждый раз, когда вызывается workwork (например, с использованием :pre). Функции предварительных условий также должны быть собраны (и обработаны) в одной функции и доступны напрямую для клиентского кода (например, для отключения кнопки).

Каков идиоматический способ решить эту проблему в Clojure, избегая при этом дублирования кода?

В частности, есть ли способ оценить предварительные условия функции без запуска тела функции?


person 4ZM    schedule 28.03.2015    source источник


Ответы (2)


Вы можете просто собрать свои предварительные условия в функцию:

(defn foo-pre [x]
  (even? x))

Затем вызовите функцию в предварительном условии в стиле :pre:

(defn foo [x]
  {:pre [(foo-pre x)]}
  …)

Для функций, введенных с использованием defn, вы можете извлечь предварительные условия в стиле :pre из метаданных в Var:

(-> #'foo meta :arglists first meta)
;= {:pre [(foo-pre x)]}

И аналогично для :arglists записей для любых других аритетов.

Здесь есть две оговорки:

  1. Автоматически сгенерированная запись :arglists в метаданных Var может быть переопределена. Переопределение :arglists приводит к тому, что указанные выше полезные автоматически сгенерированные метаданные будут удалены.

  2. Значение {:pre [(foo-pre x)]}, возвращаемое вышеприведенным выражением (-> #'foo meta …), содержит foo-pre в качестве буквального символа — вы обязаны выяснить, к какой функции оно относится в точке определения foo. (Это может быть, а может и не быть — например, foo может быть defn внутри формы let или letfn верхнего уровня, где foo-pre является локальной функцией.)

И, наконец, анонимные функции могут использовать :pre и :post, но в настоящее время нет механизма их извлечения из самой функции.

person Michał Marczyk    schedule 28.03.2015

чтобы оценить предварительное условие функции без запуска тела функции, вы можете использовать robert-hooke библиотеку https://github.com/technomancy/robert-hooke/


    (use 'robert.hooke)

    (defn workwork [x] ...)

    (defn workwork-precondition-1 
      [f x]
      (if (precondition-1-satisfied? x)
        (f x)
        :precondition-1-not-satisfied))

    (add-hook #'workwork #'workwork-precondition-1)

person mavbozo    schedule 29.03.2015