Skip to content

Instantly share code, notes, and snippets.

@david-mcneil
Last active September 27, 2017 09:55
Show Gist options
  • Save david-mcneil/a46b091c05a91adb8336 to your computer and use it in GitHub Desktop.
Save david-mcneil/a46b091c05a91adb8336 to your computer and use it in GitHub Desktop.
examples of prismatic schema extension to higher order functions
;; (:require [lonocloud.step.async.pschema :as s])
;; Define a higher-order function. Note the 'format-f' argument that is specified to be a function
;; of one arity that takes a String and an s/Int to produce a String
(s/defn write-person [format-f :- (s/fn String [String s/Int])
person :- {:name String
:age s/Int}]
(format-f (:name person) (:age person)))
(def joe {:name "joe" :age 19})
;; Define a function whose type signature matches what the higher-order function specifies.
(s/defn simple-format :- String
[name :- String
age :- s/Int]
(str name " " age))
(write-person simple-format joe)
;; => "joe 19"
(s/defn other-fn :- String [name :- String])
(write-person other-fn joe)
;; => ExceptionInfo Input to write-person does not match schema: [(named [#<...$eval70697$other_fn__70698...$eval70697$other_fn__70698@2c073f78> not "typed function {:output-schema java.lang.String, :input-schemas [[java.lang.String Int]]}"] format-f) nil]
;; Alternatively, if we invoke the higher-order function with a parameter that does not have type
;; information, then it is assumed to be of the correct type.
(write-person (fn [n a] (str n a)) joe)
;;=> "joe19"
;; If a function has more arities than are specified in the higher-order function ...
(s/defn another-format :- String
([name :- String]
(str "name: " name))
([name :- String
age :- s/Int]
(str "name: " name " age: " age))
([name :- String
age :- s/Int
job :- String]
(str "name: " name " age: " age " job: " job)))
;; ... then it works.
(write-person another-format joe)
;; => "name: joe age: 19"
;; A higher-order function can specify that multiple arities are needed.
(s/defn write-person-2 [format-f :- (s/fn String
[String s/Int]
[String s/Int String])
person :- {:name String
:age s/Int}]
(format-f (:name person) (:age person)))
;; As long as the provided function parameter matches all of the arities then it will pass
;; validation.
(write-person-2 another-format joe)
;; => "name: joe age: 19"
(write-person other-fn joe)
;; => ExceptionInfo Input to write-person-2 does not match schema: ...
;; Varargs are supported in parameter functions.
(s/defn flexible-format :- String
[name :- String
age :- s/Int
& other :- [String]]
(str name " " [age other]))
(write-person-2 flexible-format joe)
;; => "joe [19 nil]"
;; Varargs are also supported in the higher-order function argument specifications.
(s/defn write-person-3 [format-f :- (s/fn String
[String s/Int]
[String s/Int String & [String]])
person :- {:name String
:age s/Int}]
(format-f (:name person) (:age person) "..."))
;; Note in this case the varargs occur at different positions, but the call is still allowed. The
;; tool understands how to expand the varargs to make the signatures match.
(write-person-3 flexible-format joe)
;; => "joe [19 (\"...\")]"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment