Option Types
Option types are useful when you
want to internalize reasoning about partial functions. A simple motivating
example is division over integers, for which n/0 is undefined.
The basic idea is as follows: given a partial function f : A -> B, we form the
type Option(B) by extending B with an element representing a missing value,
None, and lift each value b in B to Some(b), allowing us to represent
the partial function pf : A -> Option(B), such that, for each a in A,
pf(a) = Some(f(a)) iff f(a) is defined, and None otherwise.
Apalache leverages its support for variants to define a polymorphic option type along with some common utility functions in the module Option.tla.
The module defines a type alias $option as
\* @typeAlias: option = Some(a) | None(UNIT);
However, due to the current lack of support for polymorphic aliases, this alias
has limited utility, and parametric option types can only be properly expressed
by writing out the full variant type Some(a) | None(UNIT).
Nonetheless, in this manual page, we will sometimes write $option(a)
as a shorthand for the type Some(a) | None(UNIT).
In the context of TLA+, our encoding of option types is generalized over
"partial operators", meaning operators which return a value of type
$option(a). Support for partial functions is supplied by two operators,
OptionPartialFun and OptionFunApp.
Operators
Constructing present optional values
Notation: Some(v)
LaTeX notation: same
Apalache type: (a) => Some(a) | None(UNIT), for some type a.
Arguments: The value v of type a to be lifted into the
option.
Effect: Produces a new value of the optional type.
Determinism: Deterministic.
Errors: No errors.
Example in TLA+:
\* @type: Some(Int) | None(UNIT);
SomeInt == Some(42)
Constructing absent optional values
Notation: None
LaTeX notation: same
Apalache type: Some(a) | None(UNIT), for some type a.
Arguments: None
Effect: Produces a representation of an absent value.
Determinism: Deterministic.
Errors: No errors.
Example in TLA+:
\* @type: Some(Int) | None(UNIT);
NoInt == None
Checking for presence or absence of a value
Notation: IsSome(o) or IsNone(o)
LaTeX notation: same
Apalache type: (Some(a) | None(UNIT)) => Bool, for some type a.
Arguments: One argument: a value of type $option(a) for some type a.
Effect: These operators are TRUE or FALSE depending on whether the
optional value is present or absent, in the expected way.
Determinism: Deterministic.
Errors: No errors.
Example in TLA+:
TRUE = IsSome(Some(5)) /\ IsNone(None)
Case analysis and elimination of optional values
Notation: OptionCase(o, caseSome, caseNone)
LaTeX notation: same
Apalache type: (Some(a) | None(UNIT), a => b, UNIT => b) => b,
for some types a and b.
Arguments:
oan optional valuecaseSomeis an operator to be applied to a present valuecaseNoneis an operator to be applied to theUNITif the value is absent
Effect: OptionCase(o, caseSome, caseNone) is caseSome(v) if o = Some(v), or else caseNone(UNIT). This is a way of eliminating a value of type
Option(a) to produce a value of type b.
Determinism: Deterministic.
Errors: No errors.
Example in TLA+:
/\ LET
\* @type: Int => Int;
caseSome(x) == x + 1
IN LET
\* @type: UNIT => Int;
caseNone(u) == 0
IN
OptionCase(Some(3), caseSome, caseNone) = 4
/\ LET
\* @type: Int => Str;
caseSome(x) == "Some Number"
IN LET
\* @type: UNIT => Str;
caseNone(u) == "None"
IN
OptionCase(None, caseSome, caseNone) = "None"
Sequencing application of partial operators
Notation: OptionFlatMap(f, o)
LaTeX notation: same
Apalache type:
(a => Some(b) | None(UNIT), Some(a) | None(UNIT)) => Some(b) | None(UNIT),
for some types a and b.
Arguments:
fis a partial operatoroan optional value
Effect: OptionFlatMap(f, o) is f(v) if o = Some(v), or else None.
Determinism: Deterministic.
Errors: No errors.
Example in TLA+:
LET incr(n) == Some(n + 1) IN
LET fail(n) == None IN
LET q == OptionFlatMap(incr, Some(1)) IN
LET r == OptionFlatMap(incr, q) IN
LET s == OptionFlatMap(fail, r) IN
/\ r = Some(3)
/\ s = None
Unwrapping optional values
Notation: OptionGetOrElse(o, default)
LaTeX notation: same
Apalache type: (Some(a) | None(UNIT), a) => a, for some type a.
Arguments:
oan optional valuedefaultis a default value to return
Effect:
OptionGetOrElse(o, default) is v iff o = Some(v), or else default.
Determinism: Deterministic.
Errors: No errors.
Example in TLA+:
\* @type: Set(Int) => Some(Int) | None(UNIT);
MaxSet(s) ==
LET max(oa, b) ==
IF OptionGetOrElse(oa, b) > b
THEN oa
ELSE Some(b)
IN
ApaFoldSet(max, None, s)
Converting optional values
Converting to sequences
Notation: OptionToSeq(o)
LaTeX notation: same
Apalache type: (Some(a) | None(UNIT)) => Seq(a), for some type a.
Arguments:
oan optional value
Effect: OptionToSeq(o) is <<v>> iff o = Some(v), or else <<>>.
Determinism: Deterministic.
Errors: No errors.
Example in TLA+:
LET \* @type: Seq(Int);
empty == <<>>
IN
/\ OptionToSeq(None) = empty
/\ OptionToSeq(Some(1)) = <<1>>
Converting to sets
Notation: OptionToSet(o)
LaTeX notation: same
Apalache type: (Some(a) | None(UNIT)) => Seq(a), for some type a.
Arguments:
oan optional value
Effect: OptionToSet(o) is like OptionToSeq, but producing a set.
Determinism: Deterministic.
Errors: No errors.
Example in TLA+:
LET \* @type: Set(Int);
empty == {}
IN
/\ OptionToSet(None) = empty
/\ OptionToSet(Some(1)) = {1}
Obtaining an optional value from a set
Notation: OptionGuess(s)
LaTeX notation: same
Apalache type: Set(a) => Some(a) | None(UNIT), for some type a.
Arguments:
sis a set
Effect: OptionGuess(s) is None if s = {}, otherwise it is Some(x),
where x \in s. x is selected from s nondeterministically.
Determinism: Nondeterministic.
Errors: No errors.
Example in TLA+:
LET
\* @type: Set(Int);
empty == {}
IN
/\ OptionGuess(empty) = None
/\ LET choices == {1,2,3,4} IN
LET choice == OptionGuess(choices) IN
VariantGetUnsafe("Some", choice) \in choices
Apply a function to a partial value
Notation: OptionFunApp(f, o)
LaTeX notation: same
Apalache type: (a -> b, Some(a) | None(UNIT)) => Some(b) | None(UNIT)
Arguments:
fis a functionois an optional value
Effect:
OptionFunApp(f, o) is Some(f[v]) if o = Some(v) or else None.
Determinism: Deterministic.
Errors: No errors.
Example in TLA+:
LET f == [x \in 1..3 |-> x + 1] IN
/\ OptionFunApp(f, Some(1)) = Some(2)
/\ OptionFunApp(f, None) = None
Extend a total function into a partial function
Notation: OptionPartialFun(f, undef)
LaTeX notation: same
Apalache type: (a -> b, Set(a)) => (a -> Some(b) | None(UNIT))
Arguments:
fis a total functionundefis a set of values for which the new function is to be "undefined"
Effect: OptionPartialFun(f, undef) is a function mapping each value in
undef to None, and each value x \in (DOMAIN f \ undef) to Some(f[x]).
This can be used to extend a total function into a "partial function"
whose domain is extended to include the values in 'undef'.
Determinism: Deterministic.
Errors: No errors.
Example in TLA+:
LET def == 1..3 IN
LET undef == 4..10 IN
LET f == [x \in def |-> x + 1] IN
LET pf == OptionPartialFun(f, undef) IN
/\ \A n \in def: pf[n] = Some(n + 1)
/\ \A n \in undef: pf[n] = None