-
Notifications
You must be signed in to change notification settings - Fork 9
Recommended setup
Note: updated to 2.0
The structural-typing.type
namespace contains both functions that create types and also those that check them. That's convenient for examples and playing around at the repl. In your code, I recommend you isolate type creation in one namespace, create in it checking functions that hide the type repo, and require
that namespace in all the rest of your code.
Here is a simple example. For variety, the type-repo is changed so that it throws an exception on error, rather than printing the error explanation to standard error.
(ns definition
"An example of creating your own type namespace"
;; Because this is all about tailoring structural-typing, the rare `:refer :all` is appropriate:
(:use structural-typing.type)
;; Additional predefined predicates live here:
(:require [structural-typing.preds :as pred])
;; They're not actually used in this example.
)
(def type-repo
(-> empty-type-repo
(replace-error-handler throwing-error-handler)
(named :Point
(requires :x :y)
{:x integer? :y integer?})))
Other namespaces could use this type repo like this:
(require '[structural-typing.type :as type])
(require 'myapp.mytypes :as mytypes)
(type/built-like mytypes/type-repo :Point ok)
That's pretty awkward:
- Requiring two namespaces to make use of one idea - checking my types?
- There are two entities - the namespace and the type repo - that really stand in for the same idea.
Instead, we arrange for modified versions of all the usual type-checking functions to be exported from mytypes
, by adding this to its end:
(ensure-standard-functions type-repo)
Now other namespaces can do all of the following:
(require 'myapp.mytypes :as mytypes)
(def ok {:x 1 :y 1})
(mytypes/built-like? :Point ok)
(mytypes/built-like :Point ok)
(mytypes/<>built-like ok :Point)
(mytypes/all-built-like :Point [ok ok])
(mytypes/<>all-built-like [ok ok] :Point)