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.2.0.
deps.edn JAR dependency information:
org.typedclojure/typed.clj.spec {:mvn/version "1.2.0"}
deps.edn Git dependency information:
- Note: use
clj -Sresolve
to resolve the:git/tag
to a:git/sha
org.typedclojure/typed.clj.spec
{:git/url "https://github.com/typedclojure/typedclojure"
:deps/root "typed/clj.spec"
:git/tag "1.2.0"}
Leiningen dependency information:
[org.typedclojure/typed.clj.spec "1.2.0"]
Maven dependency information:
<dependency>
<groupId>org.typedclojure</groupId>
<artifactId>typed.clj.spec</artifactId>
<version>1.2.0</version>
</dependency>
Copyright © Ambrose Bonnaire-Sergeant, Rich Hickey & contributors.
Licensed under the EPL (see the file epl-v10.html).