interstar
interstar

Reputation: 27206

How do I write a Clojure Spec for a function that takes a sequence argument?

I'm writing a function that takes a sequence of Triangles (which are in fact represented as maps).

My spec is :

(s/fdef triangle-list-to-pattern
        :args (s/cat :trs (s/* ::maths/Triangle))
        )

And the function takes a single argument, trs which is a sequence of Triangles.

However, when I instrument this function and call it I get the following failure :

fails spec: :patterning.maths/Triangle at: [:args :trs] predicate: map?

If I explicitly test the argument I'm passing to the function with spec, it passes. It really is just a sequence of things that meet the Triangle criteria.

The function seems to be working. The argument seems to be correct, and passes the spec when tested separately. So I presume I'm getting the fdef wrong somehow.

What's the problem?

Note, ::Triangle is defined :

(s/def ::Triangle (s/keys :req-un [::A ::B ::C ::a ::b ::c ::ax ::ay ::bx ::by ::cx ::cy]))

Upvotes: 3

Views: 260

Answers (1)

Taylor Wood
Taylor Wood

Reputation: 16194

The reason your :args spec isn't working is that regex specs compose to describe a single sequence when nested.

You can escape this behavior by wrapping your inner regex spec s/* in s/spec:

(s/cat :trs (s/spec (s/* ::maths/Triangle)))

Or use a different, non-regex spec to describe the sequence argument:

(s/cat :trs (s/coll-of ::maths/Triangle))

Your example spec would work if your function was variadic, because s/cat and s/* are composing to describing a single sequence with zero or more elements.

(defn adder [& nums] (apply + nums))
(s/fdef adder :args (s/cat :nums (s/* int?)))
(st/instrument `adder)
(adder 1 2 3)

Upvotes: 4

Related Questions