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
2020-06-01T01:21:51.087100Z

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 😅

2020-06-01T01:24:02.088500Z

My first question is can you compose specs together like (def ::leaf ...) (def ::node ...) (def ::tree (s/or empty? ::leaf :;node))?

seancorfield 2020-06-01T01:30:38.089100Z

I think you'd need "tagged" data structures and multi-spec for that @jayzawrotny

2020-06-01T01:31:30.089600Z

Ah thanks for the pointer!

2020-06-01T01:54:59.089900Z

Looks like someone had started down that path https://github.com/bluesxman/adt-spec/blob/master/src/adt_spec/core.clj

2020-06-01T02:32:31.090400Z

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))))

2020-06-01T02:33:03.090700Z

That's really close I think!

2020-06-01T02:44:17.090900Z

(s/def ::tree (s/or :empty empty?
                    :node (s/tuple (s/? ::tree) (s/? ::tree))
                    :leaf number?))

2020-06-01T02:45:41.091200Z

It's getting [] => :empty, but failing on anything else

2020-06-01T02:56:55.091400Z

(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)]

2020-06-01T02:57:03.091600Z

Got it!

plexus 2020-06-01T14:55:57.093100Z

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

👍 3
plexus 2020-06-01T14:56:52.093800Z

maybe that's useful to someone 🙂