clojure-spec

About: http://clojure.org/about/spec Guide: http://clojure.org/guides/spec API: https://clojure.github.io/spec.alpha/clojure.spec.alpha-api.html
niclasnilsson 2020-05-25T06:32:03.043300Z

@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}]

valerauko 2020-05-25T07:43:34.043800Z

i haven't tried this, but would an alias work? eg.

(s/def ::expression ::expr)
(s/def ::expr
  ; ...
  :left ::expression
  :right ::expresssion)))

2020-05-25T08:20:24.044Z

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 ?

niclasnilsson 2020-05-25T11:10:17.044200Z

@vale, nope, unforturnately doesn’t work.

😢 1
niclasnilsson 2020-05-25T11:11:23.044400Z

@charles.fourdrignier, this is spec 2, but I’ve tried previously on the spec that’s in the box with 1.10 as well.

2020-05-25T11:31:13.045500Z

Sorry, I don't get you were using Spec 2.

niclasnilsson 2020-05-25T11:40:27.045700Z

But it seems to work in spec 1, even without the any? trick. Very odd?

2020-05-25T11:44:24.045900Z

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.

niclasnilsson 2020-05-25T11:28:57.045400Z

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)

alexmiller 2020-05-25T12:45:02.046700Z

There are some known issues with eager spec dereferencing in spec 2

niclasnilsson 2020-05-25T13:20:29.047200Z

Ah, ok. Thanks @alexmiller.