Я использую clojure.spec
для разбора DSL.К сожалению, время вычислений для тестирования, если что-то соответствует моей спецификации, кажется, растет в геометрической прогрессии.Я хотел бы понять, почему и как решить эту проблему.
Вот как выглядит спецификация:
(spec/def ::settings map?)
(spec/def ::header (spec/spec
(spec/cat :prefix #{:begin-example}
:label string?
:settings (spec/? ::settings))))
(def end-block [:end-example])
(spec/def ::not-end (partial not= end-block))
(spec/def ::end #{end-block})
(spec/def ::block (spec/cat
:header ::header
:data (spec/* ::not-end)
:suffix ::end))
(spec/def ::form (spec/alt :block ::block
:form any?))
(spec/def ::forms (spec/* ::form))
Для того, чтобы выполнить спецификацию, я написал небольшую функцию, которая производит действительные данные для спецификации и параметр размера для управления размером данных:
(defn make-sample-data [size]
(transduce
(comp (take size)
cat)
conj
[]
(repeat [:a 1 :b :c [:begin-example "a" {:indent 4}] :d :e [:end-example] 9])))
(make-sample-data 1)
;; => [:a 1 :b :c [:begin-example "a" {:indent 4}] :d :e [:end-example] 9]
(make-sample-data 2)
;; => [:a 1 :b :c [:begin-example "a" {:indent 4}] :d :e [:end-example] 9 :a 1 :b :c [:begin-example "a" {:indent 4}] :d :e [:end-example] 9]
Теперь я выполняю этот код:
(dotimes [i 13]
(assert (time (spec/valid? ::forms (make-sample-data i)))))
, которыйпроизводит следующий вывод:
"Elapsed time: 0.077095 msecs"
"Elapsed time: 0.333636 msecs"
"Elapsed time: 0.864481 msecs"
"Elapsed time: 2.198994 msecs"
"Elapsed time: 4.432004 msecs"
"Elapsed time: 9.026142 msecs"
"Elapsed time: 17.709151 msecs"
"Elapsed time: 35.201316 msecs"
"Elapsed time: 73.178516 msecs"
"Elapsed time: 138.93966 msecs"
"Elapsed time: 288.349616 msecs"
"Elapsed time: 569.471181 msecs"
"Elapsed time: 1162.944497 msecs"
Мне кажется, что для каждого шага параметра размера время вычисления удваивается.
Мой вопрос: Как я могу изменить мою спецификацию так, чтобы время проверки было линейным с размером моих данных?