For Development HEAD DRAFTSearch (procedure/syntax/module):

11.42 srfi.189 - Maybe and Either: optional container types

Module: srfi.189

Maybe and Either types are immutable container types that can “wrap” zero or more values. Maybe can be used in the context where the value(s) may be missing (as opposed to “zero values”). Either can be used in the context where the value(s) can be correct ones or erroneous ones.

If you’re familiar with functional languages like Haskell, you may already know them. They are useful when used in the monadic pattern; that is, you can code as if the chain of calculations never fails, yet whenever the calculation fail at one place, the rest of chain is canceled and just the failure is returned.

Maybe is a union of two types, Just and Nothing. Just wraps valid value(s), while Nothing indicates there’s no meaningful values. Either is a union of two types, Right and Left. Right wraps valid value(s), while Left indicates an error, carrying some information as its payload.


11.42.1 Types and predicates

Class: <maybe>
Class: <just>
Class: <nothing>

{srfi.189} Maybe classes. <just> and <nothing> are subclasses of <maybe>. An instance of <just> carries zero or more values (payload), while an instance of <nothing> doesn’t carry information.

The <maybe> class is an abstract class and can’t create an instance of its own. Instances of <just> and <nothing> should be created with constructor procedures just and nothing.

Class: <either>
Class: <right>
Class: <left>

{srfi.189} Either classes. <right> and <left> are subclasses of <either>. An instance of either class carry zero or more values (payload); it is customary to use <right> to propagate the legitimate results of compuation, while use <left> to propagate erroneous conditions whose payload describes what’s wrong.

The <either> class is an abstract class and can’t create an instance of its own. Instances of <right> and <left> should be created with constructor procedures right and left.

Function: maybe? obj
Function: just? obj
Function: nothing? obj

[SRFI-189]{srfi.189} Type predicates. Returns #t iff obj is a Maybe, a Just, or a Nothing, respectively.

Function: either? obj
Function: right? obj
Function: left? obj

[SRFI-189]{srfi.189} Type predicates. Returns #t iff obj is a Either, a Right, or a Left, respectively.

Function: maybe= elt= maybe1 maybe …

[SRFI-189]{srfi.189} Equality predicate of Maybes. It returns #t iff all of maybe1 maybe … are Nothings, or Justs with their respective payload objects are the same using elt=.

Function: either= elt= either1 either …

[SRFI-189]{srfi.189} Equality predicate of Eithers. It returns #t iff all of either11 either … are the same types (all Rights, or all Lefts), with respective payload objects are the same using elt=.


11.42.2 Constructors

Function: just obj …

[SRFI-189]{srfi.189} Returns a Just with obj … as its payload.

Function: nothing

[SRFI-189]{srfi.189} Returns a Nothing.

Function: right obj …
Function: left obj …

[SRFI-189]{srfi.189} Returns a Right or a Left respectively, with obj … as its payload.

Function: list->just objs
Function: list->right objs
Function: list->left objs

[SRFI-189]{srfi.189} Returns a Just, Right or Left respectively, with objs as its payload.

Function: maybe->either maybe obj …

[SRFI-189]{srfi.189} The maybe argument must be a Maybe. If it is a Just, then a Right with the same payload is returned. If it is a Nothing, a Left with obj … as its payload.

Function: either->maybe either

[SRFI-189]{srfi.189} The either argument must be an Either. If it is a Right, then a Just with the same payload is returned. If it is a Left, a Nothing is returned.

Function: either-swap either

[SRFI-189]{srfi.189} The either argument must be an Either. If it is a Right, a Left with the same payload argument is returned. If it is a Left, a Right with the same payload argument is returned.


11.42.3 Accessors

Function: maybe-ref maybe failure :optional success

[SRFI-189]{srfi.189} The maybe arugment must be a Maybe. If it’s a Nothing, a procedure failure is tail-called with no arguments. If it’s Just, a procedure success is tail-called with its payload object(s). If success is omitted, values is used.

(maybe-ref (just 1 2) (^[] (error 'huh?)) +)
  ⇒ 3
Function: either-ref either failure :optional success

[SRFI-189]{srfi.189} The either argument must be an Either. If it’s a Left, a procedure failure is called with its payload object(s). If it’s a Right, a procedure success is called with its payload object(s). If success is omitted, values is used.

Function: maybe-ref/default maybe default …

[SRFI-189]{srfi.189} The maybe argument must be a Maybe. If it’s a Nothing, default … are returned as multiple values. If it’s a Just, its payload object(s) is/are returned as multiple values.

Function: either-ref/default maybe default …

[SRFI-189]{srfi.189} The either argument must be an Either. If it’s a Left, default … are returned as multiple values (the Left’s payload is discarded). If it’s a Right, its payload object(s) is/are returned as multiple values.

Function: maybe-join maybe

[SRFI-189]{srfi.189} If maybe is a Nothing, it is returned. If it’s a Maybe and its only payload is a Maybe, the inner Maybe is returned. Other cases raise an error.

Function: either-join either

[SRFI-189]{srfi.189} If either is a Left, it is returned. If it is a Right and its only payload is an Either, the inner Either is returned. Other cases raise an error.

Function: maybe-bind maybe mproc mproc2 …

[SRFI-189]{srfi.189} Monadic bind operation. The maybe argument must be a Maybe. If it is a Nothing, it is returned. If it is a Just, its payload object(s) is/are applied to a procedure mproc, which must return a Maybe. If mproc2 … are given, the same operation is repeated on them.

(maybe-bind m p p2)
  ≡ (maybe-bind (maybe-bind m p) p2)
Function: either-bind either mproc mproc2 …

[SRFI-189]{srfi.189} Monadic bind operation. The either argument must be an Either. If it is a Left, it is returned as is. If it is a Right, its payload object(s) is/are applied to a procedure mproc, which must return an Either. If mproc2 … are given, the same operation is repeated on them.

(either-bind e p p2)
  ≡ (either-bind (either-bind e p) p2)
Function: maybe-compose mproc mproc2 …
Function: either-compose mproc mproc2 …

[SRFI-189]{srfi.189} Each argument must be a procedure taking zero or more arguments and return a Maybe/an Either. Returns a procedure that accepts zero or more arguments and returns a Maybe/an Either.

When the returned procedure is called, it first calls mproc; if it returns a Nothing/Left, or there’s no more mprocs, the result is returned. If the result is a Just, its payload is applied to the next mproc, and so on.

(maybe-bind m p p2 ...)
  ⇒ (maybe-ref m (^[] (nothing))
              (maybe-compose p p2 ...))

11.42.4 Sequence operations

A Maybe and an Either can be a container of zero or one element, and we have several procedures that employ this view. (Note: For this purpose, we treat multiple payload values as a whole, since they are processed in one step—as if we don’t regard multiple procedure arguments and multiple return values as a sequence of individual values.)

Function: maybe-length maybe
Function: either-length either

[SRFI-189]{srfi.189} Returns 0 if maybe/either is a Nothing/Left, and 1 if it is a Just/Right. An error is thrown if the argument isn’t a Maybe/an Either.

Function: maybe-filter pred maybe
Function: either-filter pred either obj …

[SRFI-189]{srfi.189} If maybe/either is a Nothing/Left, returns a Nothing/a Left of obj …. If maybe/either is a Just/a Right, apply pred on its payload value(s). If pred returns a true value, maybe/either is returned; otherwise, a Nothing/a Left of obj … is returned.

An error is thrown if maybe/either isn’t a Maybe/an Either.

Function: maybe-remove pred maybe
Function: either-remove pred either obj …

[SRFI-189]{srfi.189} Like maybe-filter/either-filter, but the meaning of pred is reversed.

Function: maybe-sequence mappable cmap :optional aggregator
Function: either-sequence mappable cmap :optional aggregator

[SRFI-189]{srfi.189} This converts a collection of Maybes/Eithers to a Mayber/an Either of a collection. The input collection and the collection in the output can be of different type.

It’s easier to explain using Haskell-ish type signatures, although it’s not precisely specified. Suppose Container x is some kind of a collection of type x, and a* is multiple values of arbitrary types.

Mappable   = Container Maybe a*
CMap       = ((Maybe a* -> b) -> Container Maybe a* -> Container' b
Aggregator = a* -> b

maybe-sequence :: Mappable -> CMap -> Aggregator -> Container' b

The cmap maps proc over the input container (mappable), and gathers the result into another container. It can be any containers, as long as it matches the mappable argument. For example, mappable may be a vector of Maybes, and cmap can be vector-map–in that case, both Container and Container' are Vector. Or, mappable may be a list of Maybes, and cmap can be (cut map-to <string> <> <>), then Container is a list and Container' is a string.

The types a* and b is determined by the aggregator procedure, whose default value is list.

Function: maybe-map proc maybe
Function: either-map proc either

[SRFI-189]{srfi.189} If maybe/either is a Nothing/Left, it is returned as is. If it is a Just/Right, its payload value(s) is/are passed to proc, and the result is returned.

Function: maybe-for-each proc maybe
Function: either-for-each proc either

[SRFI-189]{srfi.189} If maybe/either is a Nothing/Left, these procedures do nothing. Otherwise, proc is applied to the argument’s payload values. The result of proc is discarded. Returns an unspecified vlaue.

Function: maybe-fold kons knil maybe
Function: either-fold kons knil either

[SRFI-189]{srfi.189} If maybe/either is a Nothing/Left, knil is returned. Otherwise, kons is called with the argument’s payload values, plus knil. What kons returns becomes the result.

Function: maybe-unfold p f g seed …
Function: either-unfold p f g seed …

[SRFI-189]{srfi.189} First, the stop predicate p is applied to seed …. If it returns a true value, a Nothing / a Left of seed … is returned. Otherwise, g is applied to seed …, which should return the same number of values as seeds, and passed to p. If p returns false, it is an error. If p returns true, mapper is applied to seed …, then the results are wrapped in a Just/Right to be returned.


11.42.5 Protocol converters

Function: maybe->list maybe

[SRFI-189]{srfi.189} If maybe is a Just, returns a list of its payload values. If it is a Nothing, an empty list is retured.

Function: list->maybe lis

[SRFI-189]{srfi.189} If lis is an empty list, a Nothing is returned. Otherwise, a Just that has elements in lis as payload values is returned.

Note that (list->maybe (maybe->list x)) isn’t an identity mapping—if x is a Just with zero payload values, you’ll get a Nothing.

Function: either->list either

[SRFI-189]{srfi.189} If either is a Right, returns a list of its payload values. If it is a Left, returns an empty string.

Function: list->either lis obj …

[SRFI-189]{srfi.189} If lis is an empty list, a Left of obj … is returned. Otherwise, a Right that has elements in lis as payload values is returned.

Function: maybe->truth maybe

[SRFI-189]{srfi.189} If maybe is a Nothing, #f is returned. Otherwise, it must be a Just with one value, and its value is returned.

If maybe is a Just and it doesn’t have exactly one value, an error is thrown. If you want to deal with arbitrary number of payload values, use maybe->list-truth.

Function: truth->maybe obj

[SRFI-189]{srfi.189} If obj is #f, returns a Nothing. Otherwise, returns a Just with obj as its payload.

Note that (truth->maybe (maybe->truth x)) isn’t an identity mapping— if x is a Just wrapping #f, you’ll get a Nothing.

Function: either->truth either

[SRFI-189]{srfi.189} If either is a Left, #f is returned. Otherwise, it must be a Right with one value, and its value is returned.

If either is a Right and it doesn’t have exactly one value, an error is thrown. If you want to deal with arbitrary number of payload values, use either->list-truth.

Function: truth->either obj fail-obj …

[SRFI-189]{srfi.189} If obj is #f, returns a Left with fail-obj … is returned. Otherwise, returns a Right with obj as its payload.

Function: maybe->list-truth maybe

[SRFI-189]{srfi.189} Like maybe->list, it returns #f if maybe is a Nothing. If maybe is a Just, however, it returns a list of its payload values.

Function: list-truth->maybe lis-or-false

[SRFI-189]{srfi.189} The argument must be #f of a list. If it is #f, a Nothing is returned. If it is a list, a Just with elements of the list is returned.

(list-truth->maybe (maybe->list-truth x)) is an identity mapping.

Function: either->list-truth either

[SRFI-189]{srfi.189} Like either->list, it returns #f if either is a Left. If either is a Right, however, it returns a list of its payload values.

Function: list-truth->either lis-or-false fail-objs …

[SRFI-189]{srfi.189} The list-or-false argument must be #f of a list. If it is #f, a Left with fail-objs … is returned. If it is a list, a Right with elements of the list is returned.

Function: maybe->generation maybe

[SRFI-189]{srfi.189} If maybe is a Nothing, an EOF object is returned. Otherwise, it must be a Just with one value, and its value is returned. If maybe is a Just and it doesn’t have exactly one value, an error is thrown.

Function: generation->maybe obj

[SRFI-189]{srfi.189} If obj is an EOF value, a Nothing is returned. Otherwise, a Just wrapping obj is returned.

Function: either->generation either

[SRFI-189]{srfi.189} If either is a Left, an EOF object is returned. Otherwise, it must be a Right with one value, and its value is returned. If either is a Right and it doesn’t have exactly one value, an error is thrown.

Function: generation->either obj fail-objs …

[SRFI-189]{srfi.189} If obj is an EOF value, a Left with fail-objs … is returned. Otherwise, a Right wrapping obj is returned.

Function: maybe->values maybe

[SRFI-189]{srfi.189} If maybe is a Just, returns its payload as multiple values. If it is a Nothing, returns no values. (Note that a Just with zero values also returns no values.)

Function: values->maybe producer

[SRFI-189]{srfi.189} It first invokes a procedure producer with no values. If it returns zero values, a Nothing is returned; otherwise, a Just with those values are returned.

Function: either->values either

[SRFI-189]{srfi.189} If either is a Right, returns its payload as multiple values. If it is a Left, returns no values. (Note that a Right with zero values also returns no values.)

Function: values->either producer fail-obj …

[SRFI-189]{srfi.189} It first invokes a procedure producer with no values. If it returns zero values, a Left with fail-obj … as its payload is returned. If it returns one or more values, a Right with those values are returned.

Function: maybe->two-values maybe

[SRFI-189]{srfi.189} If maybe is a Just with exactly one value, the value and #t is returned. If maybe is a Nothing, two #f is returned. An error is thrown if maybe has a Just with zero or more than two values.

Function: two-values->maybe producer

[SRFI-189]{srfi.189} The inverse of maybe->two-values. A procedure producer is called with no arguments. It must return two values, a possible payload value, and a boolean. If the second value is true, a Just with the first value is returned. If the second value is #f, a Nothing is returned (the first return value is ignored).

Function: exception->either pred thunk

[SRFI-189]{srfi.189} A procedure thunk is called without argument, wrapped by an exception handler. If thunk raises a condition, it is examined by pred. If pred returns true on the condition, the exception is wrapped by a Left and returned. If pred returns #f, the exception is reraised. If no exception is raised, the result(s) of thunk is wrapped by a Right and returned.


11.42.6 Syntactic utilities

Macro: maybe-if mtest then else

[SRFI-189]{srfi.189} If the mtest expression yields a Just, evaluates then. If the mtest expression yeilds a Nothing, evaluates else. If the mtest expression doesn’t produce a Maybe, an error is thrown.

Macro: maybe-and maybe …
Macro: either-and either …

[SRFI-189]{srfi.189} Evaluates maybe/either from left to right, as far as each yields a Just/Right. If every expression yields a Just/Right, the last one is returned. If it encounters an expression that yields a Nothing/Left, it stops evaluating the rest of expressions and returns the Nothing/Left.

If expressions yield something other than Maybe/Either, an error is thrown.

Macro: maybe-or maybe …
Macro: either-or either …

[SRFI-189]{srfi.189} Evaluates maybe/either from left to right, as far as each yields a Nothing/Left. If it encounters an expression that yields a Just/Right, it stops evaluating the rest of expressions and returns it.

If expressions yield something other than Maybe/Either, an error is thrown.

Macro: maybe-let* ( claw … ) body …
Macro: either-let* ( claw … ) body …

[SRFI-189]{srfi.189} This is a Maybe/Either version of and-let*.

Each claw can be either one of the following forms:

identifier

The identifier’s value is taken. It must be a Maybe/an Either, or an error is signaled. If it is a Just/Right, evaluation proceeds to the next claw. If it is a Nothing/Left, evaluation stops and the value is returned immediately.

(identifier expression)

The expression is evaluated. It must yield a Maybe/an Either, or an error is signaled. If it is a Just/Right, identifier is bound to its payload, and the rest of claws and body are processed with the scope of identifier. If it is a Nothing/Left, evaluation stops and the value is returned immediately. An error is signaled if a Just/Right doesn’t carry exactly one value.

( expression )

The expression is evaluated. It must yield a Maybe/an Either, or an error is signaled. If it is a Just/Right, evaluation proceeds to the next claw. If it is a Nothing/Left, evaluation stops and the value is returned immediately.

After all claws are processed and none yields a Nothing/Left, body … are evaluated.

Macro: maybe-let*-values ( mv-claw … ) body …
Macro: either-let*-values ( mv-claw … ) body …

[SRFI-189]{srfi.189} Multi-value payload version of maybe-let*/either-let*.

Each claw can be either one of the following forms:

identifier

The identifier’s value is taken. It must be a Maybe/an Either, or an error is signaled. If it is a Just/Right, evaluation proceeds to the next claw. If it is a Nothing/Left, evaluation stops and the value is returned immediately.

(formals expression)

The formals is the same as the formals of the lambda form, that is, a proper or dotted list of identifiers.

The expression is evaluated. It must yield a Maybe/an Either, or an error is signaled. If it is a Just/Right, identifiers in the formals are bound with the payload of the Just/Right, and the rest of claws and body are processed with the scope of those identifiers. If it is a Nothing/Left, evaluation stops and the value is returned immediately. An error is signaled if the formals doesn’t match the payload of the Just/Right.

( expression )

The expression is evaluated. It must yield a Maybe/an Either, or an error is signaled. If it is a Just/Right, evaluation proceeds to the next claw. If it is a Nothing/Left, evaluation stops and the value is returned immediately.

After all claws are processed and none yields a Nothing/Left, body … are evaluated.

Macro: either-guard pred body …

[SRFI-189]{srfi.189} The body … is evaluated, and the value(s) it produces are wrapped in a Right and returned. If an exception occurs in body …, the thrown condition is passed to a predicate pred. If the condition satisfies the predicate, it is wrapped in a Left and returned. Otherwise, the condition is reraised with raise-continuable.


11.42.7 Trivalent logic

This section describes procedures that deal with trivalent logic—a value can be a false value (Just #f), a true value (Just with anything other than #f), and Nothing.

If any of the arguments is Nothing, the result becomes Nothing (except tri=?).

All the argument must be Maybe type, or an error is signalled.

Function: tri-not maybe

[SRFI-189]{srfi.189} Returns Just #t if maybe is trivalent-false, Just #f if maybe is triavlent-true, and Nothing if maybe is Nothing.

Function: try=? maybe …

[SRFI-189]{srfi.189} Returns Just #t if arguments are either all trivalent-true or all trivalent-false. Otherwise return Just #f. Note that if any of the argument is Nothing, the result is Just #f (even all arguments are Nothing).

Function: try-and maybe …

[SRFI-189]{srfi.189} Returns Just #t if all arguments are trivalent-true, Just #f if all arguments are Just but at least one of them is Just #f, and Nothing if any of the arguments is Nothing. If there’s no arguments, Just #t is returned.

This is not a shortcut operation like and.

Function: try-or maybe …

[SRFI-189]{srfi.189} Returns Just #f if all arguments are trivalent-false, Just #t if all arguments are Just but at least one of them is trivalent-true, and Nothing if any of the arguments is Nothing. If there’s no arguments, Just #f is returned.

This is not a shortcut operation like or.

Function: try-merge maybe …

[SRFI-189]{srfi.189} If all arguments are Nothing, Nothing is returned. Otherwise, first Just is returned.



For Development HEAD DRAFTSearch (procedure/syntax/module):
DRAFT