spec can describe and be used with arbitrary sequences. It supports this via a number of regex spec operations.

(clojure.spec/valid? (clojure.spec/cat :text string? :int int?) ["test" 1])
;;=> true

cat requires labels for each spec used to describe the sequence. cat describes a sequence of elements and a spec for each one.

alt is used to choose among a number of possible specs for a given element in a sequence. For example:

(clojure.spec/valid? (clojure.spec/cat :text-or-int (clojure.spec/alt :text string? :int int?)) ["test"])
;;=> true

alt also requires that each spec is labeled by a keyword.

Regex sequences can be composed in some very interesting and powerful ways to create arbitrarily complex sequence-describing specs. Here's a slightly more complex example:

(clojure.spec/def ::complex-seq (clojure.spec/+ (clojure.spec/cat :num int? :foo-map (clojure.spec/map-of keyword? int?))))
(clojure.spec/valid? ::complex-seq [0 {:foo 3 :baz 1} 4 {:foo 4}])
;;=> true

Here ::complex-seq will validate a sequence of one or more pairs of elements, the first being an int and the second being a map of keyword to int.