On this page:
success
failure
either?
success?
failure?
either/  c
either
from-success
from-failure
from-either
map-failure
flip-either
maybe->either
either->maybe

2.2 Either🔗ℹ

 (require data/either) package: functional-lib

The either type provides another implementation of optional values, generally used to represent computations that can fail. However, it augments just and nothing by allowing the kind of failure to be annotated. When a computation results in nothing, it clearly failed, but it is not always clear why (especially after a long chain of monadic computation).

The success constructor is exactly like just—it signals a successful value, and it can be mapped over as a functor or applicative functor and sequenced as a monad. The failure constructor has the same short-circuiting behavior of nothing, but it accepts a value like success, which can be used to annotate the kind of failure.

As an example, we can rewrite the safe- functions from the maybe section using either.

> (define (safe-/ a b)
    (if (zero? b)
        (failure "attempted to divide by zero")
        (success (/ a b))))
> (define (safe-first lst)
    (if (empty? lst)
        (failure "attempted to get the first element of an empty list")
        (success (first lst))))
> (define (safe-rest lst)
     (if (empty? lst)
         (failure "attempted to get the rest of an empty list")
         (success (rest lst))))
> (define (divide-first-two lst)
    (do [a  <- (safe-first lst)]
        [xs <- (safe-rest lst)]
        [b  <- (safe-first xs)]
        (safe-/ a b)))
> (divide-first-two '(20 11))

(success 20/11)

> (divide-first-two '(3 0))

(failure "attempted to divide by zero")

> (divide-first-two '(3))

(failure "attempted to get the first element of an empty list")

procedure

(success x)  either?

  x : any/c

procedure

(failure x)  either?

  x : any/c

procedure

(either? v)  boolean?

  v : any/c

procedure

(success? v)  boolean?

  v : any/c

procedure

(failure? v)  boolean?

  v : any/c
Value constructors and predicates for either, which are tagged optional values. The success function produces a successful value, and the failure constructor creates a value that represents failure. Success and failure values can be serialized using racket/serialize as long as the inner values are serializable.

> (success 'hello)

(success 'hello)

> (failure 'failed)

(failure 'failed)

Either values are monads that short-circuit on failure.

> (map add1 (success 1))

(success 2)

> (map add1 (failure 'failed))

(failure 'failed)

> ((pure +) (success 1) (success 2))

(success 3)

> (do [n <- (success 1)]
      (pure (add1 n)))

(success 2)

procedure

(either/c failure-ctc success-ctc)  contract?

  failure-ctc : contract?
  success-ctc : contract?
Produces a contract that accepts either values. If the value is a failure, the contained value must satisfy failure-ctc; likewise, if the value is a success, it must satisfy success-ctc.

procedure

(either failure-proc    
  success-proc    
  either-value)  any/c
  failure-proc : (any/c . -> . any/c)
  success-proc : (any/c . -> . any/c)
  either-value : maybe?
Like maybe for either values, performs a sort of “first-class pattern-match” on either-value—if either-value is (failure x), then the result is (failure-proc x). Otherwise, if either-value is (success x), then the result is (success-proc x).

> (either string-length add1 (failure "failed"))

6

> (either string-length add1 (success 1))

2

> (either string-length add1 (success 2))

3

procedure

(from-success default-value either-value)  any/c

  default-value : any/c
  either-value : either?
Equivalent to (either (const default-value) identity either-value). If either-value is a failure?, then the result is default-value. Otherwise, if either-value is (success x), then the result is x.

> (from-success #f (failure "failed"))

#f

> (from-success #f (success 18))

18

procedure

(from-failure default-value either-value)  any/c

  default-value : any/c
  either-value : either?
Equivalent to (either identity (const default-value) either-value), which is also just from-success with the sides flipped. If either-value is a success?, then the result is default-value. Otherwise, if either-value is (failure x), then the result is x.

> (from-failure #f (failure "failed"))

"failed"

> (from-failure #f (success 18))

#f

procedure

(from-either either-value)  any/c

  either-value : either?
Extracts the value from any either value; equivalent to (either identity identity either-value). If either-value is (success x), then the result is x. Otherwise, if either-value is (failure y), then the result is y.

> (from-either (failure "failed"))

"failed"

> (from-either (success 18))

18

procedure

(map-failure f e)  either?

  f : (any/c . -> . any/c)
  e : either?
Like map over either values, but flipped: it applies f to values inside of a failure instead of a success.

> (map-failure symbol->string (success 1))

(success 1)

> (map-failure symbol->string (failure 'failed))

(failure "failed")

procedure

(flip-either e)  either?

  e : either?
Converts successes into failures and vice-versa.

> (flip-either (success 'foo))

(failure 'foo)

> (flip-either (failure 'bar))

(success 'bar)

procedure

(maybe->either x m)  either?

  x : any/c
  m : maybe?
Converts m to an either value. A just is converted to a success containing the same value, and a nothing is converted to a failure containing x.

> (maybe->either 'fail (just 42))

(success 42)

> (maybe->either 'fail nothing)

(failure 'fail)

procedure

(either->maybe e)  maybe?

  e : either?
Converts e to an unannotated optional value. A success is converted to a just containing the same value, and a failure is converted to nothing.

> (either->maybe (success 42))

(just 42)

> (either->maybe (failure 'fail))

#<nothing>