srfi.189
- Maybe and Either: optional container types ¶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.
Unlike other languages, though, Just, Right and Left can carry
arbitrary number of values, reflecting Scheme’s multiple values.
Suppose you have a procedure f
that returns two values.
When you lift f
to Maybe monad, the lifted procedure mf
may return Just
with two values or Nothing
.
Although most of the time we use single value in practice, keep
that in mind to read the reference.
{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 itself 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
.
{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
.
[SRFI-189]{srfi.189
}
Type predicates.
Returns #t
iff obj is a Maybe, a Just, or a Nothing,
respectively.
[SRFI-189]{srfi.189
}
Type predicates.
Returns #t
iff obj is a Either, a Right, or a Left,
respectively.
[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=.
[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=.
[SRFI-189]{srfi.189
}
Returns a Just with obj … as its payload.
[SRFI-189]{srfi.189
}
Returns a Nothing.
[SRFI-189]{srfi.189
}
Returns a Right or a Left respectively, with obj …
as its payload.
[SRFI-189]{srfi.189
}
Returns a Just, Right or Left respectively, with
objs as its payload.
[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.
[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.
[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.
[SRFI-189]{srfi.189
}
The maybe argument 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
[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.
[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.
(maybe-ref/default maybe obj ...) ≡ (maybe-ref maybe (^[] (values obj ...)))
[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.
(either-ref/default either obj ...) ≡ (either-ref either (^ _ (values obj ...)))
[SRFI-189]{srfi.189
}
If maybe is a Nothing,
it is returned. If it’s a Just and its only payload is a Maybe,
the inner Maybe is returned. Other cases raise an error.
[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.
[SRFI-189]{srfi.189
}
Monadic bind operation. The maybe argument must be a Maybe,
and each mproc mproc2 … must be a procedure that returns
a Maybe.
If maybe 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)
[SRFI-189]{srfi.189
}
Monadic bind operation. The either argument must be an Either,
and each mproc mproc2 … must be a procedure
that returns an Either.
If either 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)
[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 ...))
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.)
[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.
[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.
[SRFI-189]{srfi.189
}
Like maybe-filter
/either-filter
, but the meaning of
pred is reversed.
[SRFI-189]{srfi.189
}
This converts a collection of Maybes/Eithers to a Maybe/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
If all the elements in the input is Justs,
the cmap maps the first argument procedure
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 vectors.
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
.
(use gauche.sequence) ; generic map (map-sequence (vector (just 'a 'b) (just 'c 'd 'e) (just 'f)) map vector) ⇒ #<Just (#(a b) #(c d e) #(f))>
If there’s Nothing in the input container, it is returned.
The operation of either-sequence
is similar, with replacing
Just/Nothing with Right/Left. If input sequence contains Lefts,
the first Left is returned as is.
[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.
(maybe-map quotient&remainder (just 18 4)) ⇒ #<Just 4 2>
[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 value.
[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.
(maybe-fold vector 'z (just 'a 'b)) ⇒ #(a b z)
[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, next seed generator 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
(since Maybe/Either as a sequence can have at most 1 element).
If p returns true, f is applied to seed …,
then the results are wrapped in a Just/Right to be returned.
[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.
(When the return value is an empty list, it can be either
maybe is Nothing, or a Just with no value.)
Note that this is not a convertion from “Maybe as a sequence”
to a list. Regarded as a sequence, a Just always contain
one element, which can have multiple values. This procedure
conceptually resembles to values->list
.
[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.
[SRFI-189]{srfi.189
}
If either is a Right, returns a list of its payload values.
If it is a Left, returns an empty list.
(When the return value is an empty list, it can be either
either is Left, or a Right with no value.)
[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.
[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
.
Note that if you get #f
, you can’t distinguish if the input
is (nothing)
or (just #f)
. This procedure can be seen as
an adaptor between Maybe interface and the traditional “quasi-maybe”
pattern used in place
of true maybe type—e.g. find
returns #f
if no elements
satisfied the predicate, but can’t handle if the element that satisfies
the predicate is #f
.
[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.
[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
.
[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.
[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.
[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.
[SRFI-189]{srfi.189
}
Like either->list
, it returns a list of payload values if
either is a Right. If either is a Left,
however, it returns #f
.
[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.
[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.
[SRFI-189]{srfi.189
}
If obj is an EOF value, a Nothing is returned.
Otherwise, a Just wrapping obj is returned.
[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.
[SRFI-189]{srfi.189
}
If obj is an EOF value, a Left with fail-objs … is returned.
Otherwise, a Right wrapping obj is returned.
[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.)
[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.
[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.)
[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.
[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.
The second value allows the caller to distinguish whether the input is
a Nothing or a Just with #f
in the payload.
[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).
[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.
[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.
[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.
[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.
[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.
[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.
[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.
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.
[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
.
[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
).
[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
.
[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
.
[SRFI-189]{srfi.189
}
If all arguments are Nothing
, Nothing
is returned.
Otherwise, first Just
is returned.