I've been working on a similar idea for replacing types. If you can specify how to take apart a type, name the parts and put them back together you can then get validators, pattern matching, recursive-descent parsing with backtracking, generic traversals, lenses and generators more or less for free. By using simple data-structures to describe the types and compiling them to clojure at the call site you can have first-class types without being penalised in performance.<p>It's still work in progress but there are working examples as of <a href="https://github.com/jamii/strucjure/commit/e0e56a25c1b880c38259f2bf59768afc7350fa9c" rel="nofollow">https://github.com/jamii/strucjure/commit/e0e56a25c1b880c382...</a><p><pre><code> (using strucjure.sugar
;; define a pattern
(def peano-pattern
(graph num ~(or ~succ ~zero)
succ (succ ~num)
zero zero))
(comment ;; desugars to
{'num (->Or (->Node 'succ) (->Node 'zero))
'succ (list 'succ (->Node 'num))
'zero 'zero})
;; define a view over that pattern
(def peano->int
(view peano-graph {'succ (fnk [num] (inc num))
'zero (fnk [] 0)}))
(peano->int 'zero) ;; => 0
(peano->int '(succ (succ zero))) ;; => 2
(peano->int '(succ (succ succ))) ;; => throws MatchFailure
)
</code></pre>
It's similar to the old ideas at <a href="http://scattered-thoughts.net/blog/2012/12/04/strucjure-motivation/" rel="nofollow">http://scattered-thoughts.net/blog/2012/12/04/strucjure-moti...</a> but significantly simpler. I'm hoping to be able to release at least the core functionality in a few weeks.
The opening paragraphs really resonated with me including that code example that can be replaced with any function I wrote yesterday.<p>A lot of my time in Clojure is spent re-reading and repl-evaluating my function implementations just to remind myself what its symbols look like. Even code I wrote an hour ago. Often I stoop to the level of caching my findings in a docstring/comment.<p><pre><code> (defn alpha-map-sum-combining-thing
"TODO: Think of better name.
Example input: {:a 1 :b 2}
Example output: {[:a :b] 3}"
[alpha-map]
...)
</code></pre>
Sometimes I can spot abstractions and patterns and protocols that unify a namespace of functions so that their inputs/outputs are obvious, but often I can't.<p>This kind of tool is essential for me.
core.typed author here.<p>It might be easy to consider Schema as "competitor" to core.typed. In fact, it's the opposite: once they play nicely together they will form a formidable bug-fighting, finely-documenting team. :)<p>core.typed has accurate compile time checking, and Schema gives an expressive contracts interface for runtime checking.<p>Once they understand each other, you can start pushing and pulling between static and dynamic checking by using both libraries to their strengths.<p>Currently, core.typed requires all vars have top level annotations. This is partly because there is no way to recover type information once inside a function body. However, if we have an entire namespace using Schema liberally, we can use schemas to recover information!<p>This means we can lean on schemas for most annotations, and rely on core.typed to catch arity mismatches, bad arguments to clojure.core functions, potential null-pointer exceptions and many more nasties at compile time.<p>Then you might start adding static annotations or removing schemas, depending on the kind of code your dealing with. You might do some "static" debugging to ask whether a schema is needed to prevent a type error. core.typed would also let you know when your contracts are insufficient to rule out type errors. Really, you're free to use both tools as you'd like.<p>Schema looks very nice, thanks for open sourcing it Prismatic folks!
What timing! I have been making this exact thing myself.<p>Would you be interested in pull requests making your api simpler? Maybe allow parameters to not have to have shapes? Perhaps allowing a syntax that allows a simple way to shapes in the meta alongside the ability to change the signature for people who don't want to couple too tightly to the library? When I showed mine to my local user group last month, that was one of their biggest requests (that I was in the middle of on mine but would be happy to attempt in yours).<p>Check my (simpler and more immature) library here
<a href="https://github.com/steveshogren/deft" rel="nofollow">https://github.com/steveshogren/deft</a>
I feel your argument against just using Scala was weak, but you guys are obviously smart and feel building Schema was the right choice. So could you elaborate a bit on the decision to stick with Clojure when your problem domain lends itself to types?
Very interesting. I have a somewhat related project called Herbert, which attempts to define a schema language for EDN.<p><a href="https://github.com/miner/herbert" rel="nofollow">https://github.com/miner/herbert</a>
pretty cool - I've used something similar for python JSON validation:<p><a href="https://code.google.com/p/jsonvalidator/" rel="nofollow">https://code.google.com/p/jsonvalidator/</a><p>but love the idea of something for validating nested data structures as well.