https://github.com/marick/structural-typing/

This is a validation or type-checking library for Clojure, playing in roughly the same space as Prismatic Schema, Bouncer, or Validateur. It was inspired by Elm's structural typing and my previous need to validate complex data structures flowing into Clojure microservices.

Here is an example of a complex-ish type declaration. It could be made more terse, but that wouldn't be useful as an example.

    (type! :Line (requires :head :tail)
                 {:color [rgb-color? not-puce?]}  ; optional by default
                 {:head  (includes :Point)
                  :tail  (includes :Point)})

(Note that `type!` mutates a "global type repo". That's nice for examples, but there's a functional interface as well.)

----------

The most common question I'm asked is how this differs from Schema. Let me immediately give you reasons to stop reading:

* Schema is roughly a superset (in terms of functionality)
* Schema supports Clojurescript, and this doesn't.

----------

If you're still here, I'll describe some of the differences in emphasis that might make this library fit your needs. (Note, though, that I haven't used Schema in a real project, so my claims about it might be ignorant.)

Here are two expressions that do the same thing:

    user=> (s/validate s/Keyword 42)    ; Schema

ExceptionInfo Value does not match schema: (not (keyword? 42)) schema.core/validator/fn--1807 (core.clj:151)

    user=> (t/built-like keyword? 42)   ; Structural-typing
    Value should be `keyword?`; it is `42`
    => nil

Several things can be seen here:

1. Schema takes a roughly conventional approach to typing (so-called "nominal typing") in which (a) there are primitive types that are "things", (b) complex types are built up from primitives, and (c) the type system looks much like those that can be checked statically.

In my library, types are entirely about satisfying predicates. There is not a "type" called Keyword; there's just Clojure's `keyword?` predicate. (Note that, until someone solves the halting problem, this throws away any hope that this type system could mesh with one that can be statically checked.)

2. By default, a Structural-typing type failure prints a message to standard output and returns nil. The reason for not throwing an exception is that I love "pipeline" or "threaded" computation:

   (-> structure
       do-this
       do-that)

Structural-typing is designed so that `built-like` can be tidily inserted into such a threaded expression:

   (some-> (built-like :MyType structure)
           do-this
           do-that)

(It's very likely that you'd override the default behavior to do something other than `println`, but you'd still return `nil`. Or, if you're monadically inclined, it's easy to make built-like return `Either` values.)

3. I have an unnatural fondness for good error messages, so the default error messages have been tweaked to be pleasing to the eye. They are also customizable.

------------

If you've read this far, I'll refer you to the documentation rather than explain more.

https://github.com/marick/structural-typing      ; README
https://github.com/marick/structural-typing/wiki ; user guide
http://marick.github.io/structural-typing/       ; API

--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- You received this message because you are subscribed to the Google Groups "Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to