 
 ;;; Own types
 
-(def own-types (-> empty-type-repo
-                   (assoc :failure-handler throwing-failure-handler)
-                   (named-internal :type-repo [:success-handler :failure-handler :formatter])))
+(def ^:private own-types
+  (-> empty-type-repo
+      (assoc :failure-handler throwing-failure-handler)
+      (named-internal :type-repo [:success-handler :failure-handler :formatter])))
 
 ;;; Side-effecting API
 
 (def ^:private global-type-repo)
 
-(defn ^:no-doc start-over! []
+(defn start-over!
+  "Reset the global type repo to its starting state: no types defined, and default
+   handling of failure and success."
+  []
   (alter-var-root #'global-type-repo (fn [_] (atom empty-type-repo))))
 (start-over!)
 
-(defn set-success-handler! [f]
+(defn set-success-handler!
+  "Change the global type repo so that `f` is called when [[checked]]
+   succeeds. `f` is given the original map or record. `f`'s return value becomes
+   the return value of `checked`.
+"
+  [f]
   (swap! global-type-repo assoc :success-handler f))
-(defn set-failure-handler! [f]
+
+(defn set-failure-handler!
+  "Change the global type repo so that `f` is called when [[checked]]
+   fails. `f` is given a list of error messages. `f`'s return value becomes
+   the return value of `checked`.
+"
+  [f]
   (swap! global-type-repo assoc :failure-handler f))
-(defn set-formatter! [f]
+
+;; This will be relevant once more of bouncer is exposed.
+(defn ^:no-doc set-formatter!
+  "If a map or record doesn't match the type, the formatter is called with 
+   two arguments. The first is a map from key to list of error messages
+   (as created by [Bouncer](https://github.com/leonardoborges/bouncer)).
+   The second is the original map or record passed to `checked`."
+  [f]
   (swap! global-type-repo assoc :formatter f))
   
-(defn named! [name keys]
+(defn named! 
+  "Modifies the global type repo to define the type `name` as being
+   a map or record containing all of the given `keys`.
+   See also [[named]].
+"
+  [name keys]
   (swap! global-type-repo named name keys))
 
-(defn coercion! [name f]
+(defn coercion! 
+  "Modify the global type repo to register function `f` as one that
+   can coerce a map or record into one matching type `name`.
+   See also [[coercion]]."
+  [name f]
   (swap! global-type-repo coercion name f))
 

     (checked @global-type-repo name kvs)))

(defn instance? 
  ([type-repo name kvs]
     (checked (assoc type-repo
                     :failure-handler (constantly false) 

(ns structural-typing.type
  "Structural types, loosely inspired by Elm's way of looking at [records](http://elm-lang.org/learn/Records.elm)."
  (:refer-clojure :exclude [instance?])
  (:require [clojure.string :as str]
            [bouncer.core :as b]
            [bouncer.validators :as v]
            [such.immigration :as immigrate]))

;;; About our type

(defn- default-formatter [error-map checked-map]
  (flatten (vals error-map)))

(defn default-failure-handler
  "This failure handler prints each error message on a separate line. It returns
   `nil`, allowing constructs like this:
   
        (some-> (type/checked :frobnoz x)
                (assoc :goodness true)
                ...)
"
  [messages]
  (doseq [s messages]
    (println s))
  nil)

(defn throwing-failure-handler 
  "In contrast to the default failure handler, this one throws a
   `java.lang.Exception` whose message is the concatenation of the
   type-mismatch messages.
   
   To make all type mismatches throw failures, do this:
   
          (type/set-failure-handler! type/throwing-failure-handler)
"
  [messages]
  (throw (new Exception (str/join "\n" messages))))

(def ^:private default-success-handler identity)

(def empty-type-repo
  "A repository that contains no type descriptions. It contains
   default behavior for both success and failure cases. Here's
   an example of changing the behavior and adding a type:
   
         (-> type/empty-type-repo
             (assoc :failure-handler type/throwing-failure-handler)
             (type/named :frobable [:left :right :arrow]))
"
  {:failure-handler default-failure-handler
   :success-handler default-success-handler
   :formatter default-formatter})

(declare ^:private own-types)

