-
Notifications
You must be signed in to change notification settings - Fork 9
Using the Either monad
(The examples below can be found in the examples directory.)
Instead of reporting errors to some out-of-band stream and using a nil
return value to short-circuit further computation, you might want to use an Either monad to pass error explanations upstream. You do this by providing different functions to handle the success and error cases.
Here's a simple example, using the recommended setup:
(ns my-types
(:require [structural-typing.type :as type]
[structural-typing.assist.oopsie :as oopsie]
[blancas.morph.monads :as m])
...)
(def type-repo
(-> empty-type-repo
...
(replace-success-handler m/right)
(replace-error-handler
(oopsie/mkfn:apply-to-explanation-collection m/left))))
Now built-like
applied to a valid candidate will no longer return it. Instead, it will "wrap" that value in a Right
type.
user=> (require '[my.types :as type])
user=> (type/built-like :Point {:x 1, :y 1})
=> Right {:x 1, :y 1}
The case of a type failure is a little more complicated. Internally, the built-like
function produces a collection of oopsies. Each of them is about a particular predicate's reason for returning a falsey value. The use of oopsie/mkfn:apply-to-explanation-collection
above converts the collection of oopsies into a collection of explanations and then wraps them in a Left
.
user=> (type/built-like :Point {:x "1"})
Left (:x should be `integer?`; it is `1` :y must exist and be non-nil)
See monadic-define-1 for the complete definition. See monadic-use for the previous examples, as well as example of using all-built-like
to pass judgment on a collection and get error messages indexed to structures that failed.