Last active
June 11, 2016 05:13
-
-
Save rplevy/6549315a8f3fe5aea10290ed12b07ff9 to your computer and use it in GitHub Desktop.
temporal higher-order contract with clojure.spec
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(require '[clojure.spec :as s]) | |
(defn enforce [spec data-value] | |
(let [r (s/conform spec data-value)] | |
(if (= r :clojure.spec/invalid) | |
(throw (ex-info (str r) (s/explain-data spec data-value))) | |
data-value))) | |
(defn call-with-temporal-contract [f g contract-on-g] | |
(let [function-calls (atom [])] | |
(let [g' (fn [& [arg]] | |
(swap! function-calls conj arg) | |
(enforce contract-on-g @function-calls) | |
(g arg))] | |
(f g')))) | |
;; valid | |
(call-with-temporal-contract (fn [g] (g "foo") (g "bar") (g "baz")) | |
prn | |
#(< (count %) 4)) | |
;; throws because prn was called three times | |
(call-with-temporal-contract (fn [g] (g "foo") (g "bar") (g "baz")) | |
prn | |
#(< (count %) 3)) | |
;; valid because arguments of calls matched specified temporal pattern | |
(call-with-temporal-contract (fn [g] (g "foo") (g :baz) (g 1)) | |
prn | |
(s/cat :call1 string? | |
:call2 (s/? keyword?) | |
:call3 (s/? integer?))) | |
;; throws because arguments in sequence of calls did not match pattern | |
(call-with-temporal-contract (fn [g] (g "foo") (g :baz) (g :bar)) | |
prn | |
(s/cat :call1 string? | |
:call2 (s/? keyword?) | |
:call3 (s/? integer?))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment