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>