Type-like specs.
Higher-order functions often contain fine-grained dependencies between their arguments and return values. For example, the identity function requires its output to exactly match its input.
typed.clj/spec
enhances the expressivity of spec by giving you
the tools to specify such dependencies directly.
This spec metalanguage treats these
kinds of dependencies as first-class concepts, so you can
specify and generatively test your favourite higher-order functions.
The aim of this library is to combine the expressive power of a type-like syntax with the pragmatism and versatility of spec. I'm really excited about the possibilities of bringing together the advantages of both worlds.
I hope you enjoy using typed.clj/spec
!
Either:
-
Add a dependency to
typed.clj/spec
using your favourite build tool (see Releases and Dependency Information). -
Clone this repository and run
./script/repl
in thetyped/clj.spec
directory to follow along.
To use the generative testing features of typed.clj/spec
,
also add an explicit dependency to [org.clojure/test.check "1.0.0"]
(automatic if cloning this repository).
;; require these namespaces
(require '[clojure.alpha.spec :as s]
'[clojure.alpha.spec.gen :as gen]
'[typed.clj.spec :as t])
;; start writing polymorphic specs
(s/def ::identity
#_"Polymorphic type for clojure.core/identity"
(t/all :binder (t/binder :x (t/bind-tv))
:body
(s/fspec :args (s/cat :x (t/tv :x))
:ret (t/tv :x))))
;; using normal spec functions to use validate them
(assert (s/valid? ::identity identity))
(assert (s/valid? ::identity (comp first
(juxt identity identity)
(fn [x] x))))
(assert (not (s/valid? ::identity (fn [x] nil))))
;; start a repl from ./script/repl in this repo
;; and see tests for more interesting specs.
;; eg.,
(require '[typed-test.clj.spec.transducers :as x])
;; is (map inc) a transducer from integer? to integer? (yes)
(assert
(binding [s/*fspec-iterations* 5]
(s/valid? (t/tapp ::x/Transducer {:in integer?
:out integer?})
(map inc))))
;; is (map str) a transducer from integer? to symbol? (no)
(assert (not
(s/valid? (t/tapp ::x/Transducer {:in integer?
:out symbol?})
(map str))))
See doc/tutorial.md.
See tests for more examples:
- clojure.core/comp
- Transducers & Reducers
- clojure.core/identity
- clojure.core/integer?
- clojure.core/memoize
- clojure.core/reduce
Latest stable release is 1.0.12.
deps.edn JAR dependency information:
typed.clj/spec {:mvn/version "1.0.12"}
deps.edn Git dependency information:
- Note: use
clj -Sresolve
to resolve the:tag
to a:sha
typed.clj/spec {:git/url "https://github.com/typedclojure/typedclojure"
:deps/root "typed/clj.spec"
:tag "1.0.12"}
Leiningen dependency information:
[typed.clj/spec "1.0.12"]
Maven dependency information:
<dependency>
<groupId>typed.clj</groupId>
<artifactId>spec</artifactId>
<version>1.0.12</version>
</dependency>
Copyright © Ambrose Bonnaire-Sergeant, Rich Hickey & contributors.
Licensed under the EPL (see the file epl-v10.html).