2019-02-13 21:31:47 +03:00
(deftype (Result a b)
(Success [a])
(Error [b]))
2021-07-05 15:48:35 +03:00
(doc Result "is a data type for computations that might fail with an error. It
has two constructors, `(Success <value>)` and `(Error <value>)`, and provides
many functions for working with, combining, and wrapping and unwrapping
values.")
2019-02-13 21:31:47 +03:00
(defmodule Result
2019-02-15 12:18:23 +03:00
(doc apply "takes a `Result` `a` and applies functions to them, one in the case that it is an `Error`, one in the case that it is a `Success`.")
2019-02-13 21:31:47 +03:00
(defn apply [a success-f error-f]
(match a
2020-01-14 00:36:20 +03:00
(Success x) (Success (~success-f x))
(Error x) (Error (~error-f x))))
2019-02-13 21:31:47 +03:00
2019-02-15 12:18:23 +03:00
(doc map "takes a `Result` and applies a function `f` to it if it is a `Success` type, and wraps it back up. In the case that it is an `Error`, it is returned as is.")
2019-02-13 21:31:47 +03:00
(defn map [a f]
(match a
2020-01-14 00:36:20 +03:00
(Success x) (Success (~f x))
2019-02-13 21:31:47 +03:00
(Error x) (Error x)))
2020-01-22 14:12:17 +03:00
(doc map-error "takes a `Result` and applies a function `f` to it if it is an `Error` type, and wraps it back up. In the case that it is a `Success`, it is returned as is.")
(defn map-error [a f]
(match a
(Success x) (Success x)
(Error x) (Error (~f x))))
2019-02-15 12:18:23 +03:00
(doc and-then "takes a `Result` and applies a function `f` to it if it is a `Success` type. In the case that it is an `Error`, it is returned as is.
It is thus quite similar to [`map`](#map), but it will unwrap the value.")
2019-02-13 21:31:47 +03:00
(defn and-then [a f]
(match a
2020-01-14 00:36:20 +03:00
(Success x) (~f x)
2019-02-13 21:31:47 +03:00
(Error x) (Error x)))
2019-02-15 12:18:23 +03:00
(doc unwrap-or-zero "takes a `Result` and either unwraps it if it is a `Success`, or calls `zero`. `zero` must be defined on the `Success` type.")
2019-02-13 21:31:47 +03:00
(defn unwrap-or-zero [a]
(match a
(Success x) x
(Error _) (zero)))
2019-02-15 12:18:23 +03:00
(doc or-else "takes a `Result` and applies a function `f` to it if it is an `Error` type. In the case that it is a `Success`, it is returned as is.
2019-02-13 21:31:47 +03:00
2019-02-15 12:18:23 +03:00
It is the inverse of [`and-then`](#and-then).")
2019-02-13 21:31:47 +03:00
(defn or-else [a f]
(match a
(Success x) (Success x)
2020-01-14 00:36:20 +03:00
(Error x) (~f x)))
2019-02-13 21:31:47 +03:00
2019-02-15 12:18:23 +03:00
(doc unwrap-or-else "takes a `Result` and either unwraps it if it is a `Success`, or calls a function `f` on the value contained in the `Error`.")
2019-02-13 21:31:47 +03:00
(defn unwrap-or-else [a f]
(match a
(Success x) x
2020-01-14 00:36:20 +03:00
(Error x) (~f x)))
2019-02-13 21:31:47 +03:00
2019-02-15 12:18:23 +03:00
(doc unsafe-from-success "is an unsafe unwrapper that will get the value from a `Success`. If `a` is an `Error`, a runtime error will be generated.")
2019-02-13 21:31:47 +03:00
(defn unsafe-from-success [a]
(match a
(Success x) x))
2019-02-15 12:18:23 +03:00
(doc from-success "is an unwrapper that will get the value from a `Success`. If `a` is an `Error`, a default value will be returned.")
2019-02-13 21:31:47 +03:00
(defn from-success [a dflt]
(match a
(Error _) dflt
(Success x) x))
2019-02-15 12:18:23 +03:00
(doc unsafe-from-error "is an unsafe unwrapper that will get the value from an `Error`. If `a` is a `Success`, a runtime error will be generated.")
2019-02-13 21:31:47 +03:00
(defn unsafe-from-error [a]
(match a
(Error x) x))
2019-02-15 12:18:23 +03:00
(doc from-error "is an unwrapper that will get the value from an `Error`. If `a` is a `Success`, a default value will be returned.")
2019-02-13 21:31:47 +03:00
(defn from-error [a dflt]
(match a
(Success _) dflt
(Error x) x))
2019-02-15 12:18:23 +03:00
(doc to-maybe "is a function that will convert a `Result` to a `Maybe`, where a `Success` becomes a `Just` and an `Error` becomes a `Nothing`.
The error value is thrown away.")
2019-02-13 21:31:47 +03:00
(defn to-maybe [a]
(match a
(Success x) (Maybe.Just x)
(Error _) (Maybe.Nothing)))
2019-02-15 12:18:23 +03:00
(doc success? "checks whether the given value `a` is a `Success`.
It is the inverse of [`error?`](#error?).")
2019-02-13 21:31:47 +03:00
(defn success? [a]
2020-04-30 13:57:27 +03:00
(match-ref a
2019-02-13 21:31:47 +03:00
(Error _) false
(Success _) true))
2021-06-08 22:05:51 +03:00
(doc error? "checks whether the given value `a` is an `Error`.
2019-02-15 12:18:23 +03:00
It is the inverse of [`success?`](#success?).")
2019-02-13 21:31:47 +03:00
(defn error? [a]
2020-04-30 13:57:27 +03:00
(match-ref a
2019-02-13 21:31:47 +03:00
(Error _) true
(Success _) false))
2019-02-15 12:18:23 +03:00
(doc = "equality is defined as the equality of both the constructor and the contained value, i.e. `(Success 1)` and `(Success 1)` are the same, but `(Success 1)` and `(Success 2)` are not.")
2019-02-13 21:31:47 +03:00
(defn = [a b]
2020-04-30 13:57:27 +03:00
(match-ref a
2019-02-13 21:31:47 +03:00
(Success x)
2020-04-30 13:57:27 +03:00
(match-ref b
2019-02-13 21:31:47 +03:00
(Error _) false
(Success y) (= x y))
(Error x)
2020-04-30 13:57:27 +03:00
(match-ref b
2019-02-13 21:31:47 +03:00
(Success _) false
(Error y) (= x y))))
2020-05-10 20:32:22 +03:00
(implements = Result.=)
2019-02-13 21:31:47 +03:00
)
2019-02-15 12:18:23 +03:00
(defmodule Maybe
(doc to-result "is a function that will convert a `Maybe` to a `Result`, where a `Just` becomes a `Success` and a `Nothing` becomes an `Error`.
2019-05-02 23:33:18 +03:00
You’ ll also need to provide an error message `error` that is given to the `Error` constructor if necessary.")
2019-02-15 12:18:23 +03:00
(defn to-result [a error]
(match a
(Nothing) (Result.Error error)
(Just x) (Result.Success x)))
)