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
teodorlu 2020-10-30T20:54:28.146300Z

Good evening! I've written specs to validate a small math language with addition and multiplication. Now I want to generate values! But I'm hitting Stack Overflow. I assume that's because my specs/generators are mutually recursive. Any tips for writing mutually recursive spec generators that don't blow the stack? Code attached.

teodorlu 2020-10-31T13:48:58.148400Z

Note: Tree depth can also be controlled probabilistically. Make it more probable to take the non-recursive path than the recursive path. Example from the docs:

(gen/frequency [[9 gen/small-integer] [1 (gen/return nil)]])
The probability of the non-recursive path would have to counterbalance the fanout for the recursive paths.

teodorlu 2020-10-31T14:23:13.149200Z

From reading test.check source, I see that many generators accept a size parameter. I suspect that I could have used that instead of inventing my own depth.

teodorlu 2020-10-30T22:35:16.146700Z

Idea: write generators as functions rather than directly on specs. Argument: recursion depth. Call generator functions from the spec.

teodorlu 2020-10-30T22:51:42.146900Z

Followed through on a generator namespace with recursion limit. That fixed my StackOverflow. Sample for add and multiply:

(defn add [depth]
  (gen/fmap to-list
            (gen/tuple (gen/return '+) (expression (dec depth)) (expression (dec depth)))))

(defn expression [depth]
  (if-not (pos? depth)
    (number)
    (gen/one-of [(number)
                 (multiply depth)
                 (add depth)])))

🎉 1
borkdude 2020-10-30T22:52:32.147300Z

Grasp now supports finding keywords using clojure specs while also preserving location metadata! https://github.com/borkdude/grasp#finding-keywords This should come in handy for finding re-frame events and subscriptions in CLJS apps. I also made a #grasp channel

🎉 3