A friend shared this with me http://gizmo385.github.io/clojure/programming/2015/08/11/adts-in-clojure.html which ended with a macro for (data Tree = Empty | Leaf value | Node left right)
. I'm trying to write the spec for something like that just for learning purposes. I got to (s/def ::tree (s/or empty?))
before getting a bit stuck 😅
My first question is can you compose specs together like (def ::leaf ...)
(def ::node ...)
(def ::tree (s/or empty? ::leaf :;node))
?
I think you'd need "tagged" data structures and multi-spec for that @jayzawrotny
Ah thanks for the pointer!
Looks like someone had started down that path https://github.com/bluesxman/adt-spec/blob/master/src/adt_spec/core.clj
Found from https://gist.github.com/Olical/f2b934873a49c0638ca673ab764a0131
(s/def ::element (s/or :string string?
:element (s/cat :name keyword?
:attrs (s/? (s/map-of keyword? any?))
:children (s/* ::element))))
That's really close I think!
(s/def ::tree (s/or :empty empty?
:node (s/tuple (s/? ::tree) (s/? ::tree))
:leaf number?))
It's getting [] => :empty, but failing on anything else
(ns spec-intro.core
(:require
[clojure.spec.alpha :as s]))
(s/def ::tree (s/or
:empty (s/and coll? empty?)
:node (s/cat :left (s/? ::tree)
:right (s/? ::tree))
:leaf number?))
(def tree [0 [1 [2 3]]])
[(s/conform ::tree tree)
(s/conform ::tree [1 0])
(s/conform ::tree [])
(s/conform ::tree 1)]
Got it!
regarding my question from yesterday re. infinite recursion in generators, I managed to work around it with size
/`resize`, basically making sure that nested generators get increasingly smaller size parameters, and always emitting terminal tokens at small sizes https://github.com/lambdaisland/regal/blob/master/src/lambdaisland/regal/spec_alpha.cljc#L21-L33
maybe that's useful to someone 🙂