@charles.fourdrignier, well, yes and no. It compiles then, but it still doesn’t work. The following compiles, but the expected output is not useful, and not what’s expected from a recursive spec. (see output from explain and conform)
(require '[clojure.alpha.spec :as s])
(def expr '(+ (+ 1 (* 2 "three")) 200))
(defn operator? [x] (#{'+ '- '* '/} x))
(s/def ::operator operator?)
(s/def ::operand int?)
(s/def ::expr any?)
(s/def ::expr
(s/or :operand ::operand
:expr (s/cat :operator ::operator
:left ::expr
:right ::expr)))
(s/explain ::expr expr) ;; success, but shouldn't be if recursive specs works.
(s/conform ::expr expr)
;; result
[:expr {:left (+ 1 (* 2 "three")) :operator + :right 200}]
i haven't tried this, but would an alias work? eg.
(s/def ::expression ::expr)
(s/def ::expr
; ...
:left ::expression
:right ::expresssion)))
Which Clojure did you use ? Clojure (from 1.9.0) includes clojure.spec and the namespace is different.
(require '[clojure.spec.alpha :as s])
With this namespace, it works for me (got an invalid for your expr
).
Maybe a bugfix done on clojure repository and not in the clojure/spec.alpha ?@vale, nope, unforturnately doesn’t work.
@charles.fourdrignier, this is spec 2, but I’ve tried previously on the spec that’s in the box with 1.10 as well.
Sorry, I don't get you were using Spec 2.
But it seems to work in spec 1, even without the any?
trick. Very odd?
Yes.
I use the any?
trick a couple of months ago in Spec 1.
Pretty sure some error push me to use it...
Very strange.
Hmm… But this actually seems to work in “spec 1”, (clojure 1.10.1) but not in spec 2.
(require '[clojure.spec.alpha :as s])
(def bad-expr '(+ (+ 1 (* 2 "three")) 200))
(def expr '(+ (+ 1 (* 2 3)) 200))
(defn operator? [x] (#{'+ '- '* '/} x))
(s/def ::operator operator?)
(s/def ::operand int?)
(s/def ::expr
(s/or :operand ::operand
:expr (s/cat :operator ::operator
:left ::expr
:right ::expr)))
(s/valid? ::expr bad-expr) ; false
(s/explain ::expr bad-expr) ;
(s/conform ::expr bad-expr) ; :clojure.spec.alpha/invalid
(s/valid? ::expr expr) ; true
(s/explain ::expr expr) ; success
(s/conform ::expr expr)
There are some known issues with eager spec dereferencing in spec 2
Ah, ok. Thanks @alexmiller.