This seems to me like a very practical way to approach Clojure typing. Similar to the author, I have often needed to make a series of transformations on complex objects. Those transformations mostly depended on the presence of certain keys, so having strict types was unnecessarily rigid. Derived typing would also be useful, of course.
One point to appreciate about this approach is the flexibility in only worrying about the relevant pieces. In my case, I may be worrying about whether a continuous variable has been tagged "datetime", requiring additional processing steps. Merely checking for such tags allows the input data to implicitly direct the flow of the program, reducing the coupling between data and specific processing implementations.
I've had good luck with prismatic schema https://github.com/Prismatic/schema, which seems to be along a similar direction. It's fairly low commitment and can lead to big gains fairly quickly. I assume this would be similar.
Prismatic Schema is wonderful. One useful property is that a schema is just a regular data structure (often a map). So you're free to use regular data structure processing functions:
Ditto. Augmenting my code with schema has also been a life saver in terms of documenting the input and output types of functions (e.g. complex, deeply-nested maps) so I can return to code months later and understand what's going on.
Everything that's been said is about prismatic schema is great. We've found the most benefit from using schema as a documentation tool. i.e. This is what an order-request, customer, order, etc. looks like.
Important to note that this isn't STATIC typing (which detects errors at compile-time), rather this is more like a validation library to make sure structures have certain properties at run-time.
Not saying it isn't useful, in fact I have a project in which this would be a very good fit and I might even implement it there.
Indeed. Elm implements extensible record types that can be inferred and checked statically. Similarly to object types in OCaml, which additionally supports structural subtying of of other sorts as well (e.g., polymorphic variants). It's a little strange to compare this library with Elm.
This looks like a contract library, which I assume already exists in Clojure. It'd be interesting to see what's unique about this implementation, if anything.
I've also been thinking about types, validation, and structure. I see room for various approaches, including static typing, validation, and more. For example, here's an in-progress library that I plan to build out soon: https://github.com/bluemont/shape
It would be interesting to see a "When structural-typing is better than prismatic/schema" section in the readme. I read the readme, and I don't see why you can't use something like s/validate instead of built-like. So instead of:
Our software system currently uses Redis as a central bus, and around that we have a dozen apps that send a hashmap back and forth among themselves. We use Carmine/Nippy to serialize and deserialize the hashmap, so we never have to think about anything other than a hashmap. All the bugs we face are because of missing or misused fields in the hashmap. For us, a combination of structural typing and Nippy could potentially protect us from 90% of the bugs we have seen so far.
One point to appreciate about this approach is the flexibility in only worrying about the relevant pieces. In my case, I may be worrying about whether a continuous variable has been tagged "datetime", requiring additional processing steps. Merely checking for such tags allows the input data to implicitly direct the flow of the program, reducing the coupling between data and specific processing implementations.