Option type
In programming languages (especially functional programming languages) and type theory, an option type or maybe type is a polymorphic type that represents encapsulation of an optional value; e.g., it is used as the return type of functions which may or may not return a meaningful value when they are applied. It consists of a constructor which either is empty (often named None
or Nothing
), or which encapsulates the original data type A
(often written Just A
or Some A
).
A distinct, but related concept outside of functional programming, which is popular in object-oriented programming, is called nullable types (often expressed as A?
). The core difference between option types and nullable types is that option types support nesting (e.g. Maybe (Maybe String)
≠ Maybe String
), while nullable types do not (e.g. String??
= String?
).
Theoretical aspects
In type theory, it may be written as: [math]\displaystyle{ A^{?} = A + 1 }[/math]. This expresses the fact that for a given set of values in [math]\displaystyle{ A }[/math], an option type adds exactly one additional value (the empty value) to the set of valid values for [math]\displaystyle{ A }[/math]. This is reflected in programming by the fact that in languages having tagged unions, option types can be expressed as the tagged union of the encapsulated type plus a unit type.[1]
In the Curry–Howard correspondence, option types are related to the annihilation law for ∨: x∨1=1.
An option type can also be seen as a collection containing either one or zero elements.[original research?]
The option type is also a monad where:[2]
return = Just -- Wraps the value into a maybe Nothing >>= f = Nothing -- Fails if the previous monad fails (Just x) >>= f = f x -- Succeeds when both monads succeed
The monadic nature of the option type is useful for efficiently tracking failure and errors.[3]
Examples
Agda
In Agda, the option type is named Maybe
with variants nothing
and just a
.
C++
Since C++17, the option type is defined in the standard library as template<typename T> std::optional<T>
.
Coq
In Coq, the option type is defined as Inductive option (A:Type) : Type := | Some : A -> option A | None : option A.
.
Elm
In Elm, the option type is defined as type Maybe a = Just a | Nothing
.[4]
F#
let showValue = Option.fold (fun _ x -> sprintf "The value is: %d" x) "No value" let full = Some 42 let empty = None showValue full |> printfn "showValue full -> %s" showValue empty |> printfn "showValue empty -> %s"
showValue full -> The value is: 42 showValue empty -> No value
Haskell
In Haskell, the option type is defined as data Maybe a = Nothing | Just a
.[5]
showValue :: Maybe Int -> String showValue = foldl (\_ x -> "The value is: " ++ show x) "No value" main :: IO () main = do let full = Just 42 let empty = Nothing putStrLn $ "showValue full -> " ++ showValue full putStrLn $ "showValue empty -> " ++ showValue empty
showValue full -> The value is: 42 showValue empty -> No value
Idris
In Idris, the option type is defined as data Maybe a = Nothing | Just a
.
showValue : Maybe Int -> String showValue = foldl (\_, x => "The value is " ++ show x) "No value" main : IO () main = do let full = Just 42 let empty = Nothing putStrLn $ "showValue full -> " ++ showValue full putStrLn $ "showValue empty -> " ++ showValue empty
showValue full -> The value is: 42 showValue empty -> No value
Nim
import std/options proc showValue(opt: Option[int]): string = opt.map(proc (x: int): string = "The value is: " & $x).get("No value") let full = some(42) empty = none(int) echo "showValue(full) -> ", showValue(full) echo "showValue(empty) -> ", showValue(empty)
showValue(full) -> The Value is: 42 showValue(empty) -> No value
OCaml
In OCaml, the option type is defined as type 'a option = None | Some of 'a
.[6]
let show_value = Option.fold ~none:"No value" ~some:(fun x -> "The value is: " ^ string_of_int x) let () = let full = Some 42 in let empty = None in print_endline ("show_value full -> " ^ show_value full); print_endline ("show_value empty -> " ^ show_value empty)
show_value full -> The value is: 42 show_value empty -> No value
Rust
In Rust, the option type is defined as enum Option<T> { None, Some(T) }
.[7]
fn show_value(opt: Option<i32>) -> String { opt.map_or("No value".to_owned(), |x| format!("The value is: {}", x)) } fn main() { let full = Some(42); let empty = None; println!("show_value(full) -> {}", show_value(full)); println!("show_value(empty) -> {}", show_value(empty)); }
show_value(full) -> The value is: 42 show_value(empty) -> No value
Scala
In Scala, the option type is defined as sealed abstract class Option[+A]
, a type extended by final case class Some[+A](value: A)
and case object None
.
object Main: def showValue(opt: Option[Int]): String = opt.fold("No value")(x => s"The value is: $x") def main(args: Array[String]): Unit = val full = Some(42) val empty = None println(s"showValue(full) -> ${showValue(full)}") println(s"showValue(empty) -> ${showValue(empty)}")
showValue(full) -> The value is: 42 showValue(empty) -> No value
Standard ML
In Standard ML, the option type is defined as datatype 'a option = NONE | SOME of 'a
.
Swift
In Swift, the option type is defined as enum Optional<T> { case none, some(T) }
but is generally written as T?
.[8]
func showValue(_ opt: Int?) -> String { return opt.map { "The value is: \($0)" } ?? "No value" } let full = 42 let empty: Int? = nil print("showValue(full) -> \(showValue(full))") print("showValue(empty) -> \(showValue(empty))")
showValue(full) -> The value is: 42 showValue(empty) -> No value
Zig
In Zig, add ? before the type name like ?i32
to make it an optional type.
Payload n can be captured in an if or while statement, such as if (opt) |n| { ... } else { ... }
, and an else clause is evaluated if it is null
.
const std = @import("std"); fn showValue(allocator: std.mem.Allocator, opt: ?i32) ![]u8 { return if (opt) |n| std.fmt.allocPrint(allocator, "The value is: {}", .{n}) else allocator.dupe(u8, "No value"); } pub fn main() !void { // Set up an allocator, and warn if we forget to free any memory. var gpa = std.heap.GeneralPurposeAllocator(.{}){}; defer std.debug.assert(gpa.deinit() == .ok); const allocator = gpa.allocator(); // Prepare the standard output stream. const stdout = std.io.getStdOut().writer(); // Perform our example. const full = 42; const empty = null; const full_msg = try showValue(allocator, full); defer allocator.free(full_msg); try stdout.print("showValue(allocator, full) -> {s}\n", .{full_msg}); const empty_msg = try showValue(allocator, empty); defer allocator.free(empty_msg); try stdout.print("showValue(allocator, empty) -> {s}\n", .{empty_msg}); }
showValue(allocator, full) -> The value is: 42 showValue(allocator, empty) -> No value
See also
References
- ↑ Milewski, Bartosz (2015-01-13). "Simple Algebraic Data Types" (in en). Sum types. "We could have encoded Maybe as: data Maybe a = Either () a". https://bartoszmilewski.com/2015/01/13/simple-algebraic-data-types/.
- ↑ "A Fistful of Monads - Learn You a Haskell for Great Good!". http://www.learnyouahaskell.com/a-fistful-of-monads.
- ↑ Hutton, Graham (Nov 25, 2017). "What is a Monad?". https://www.youtube.com/watch?v=t1e8gqXLbsU.
- ↑ "Maybe · An Introduction to Elm". https://guide.elm-lang.org/error_handling/maybe.html.
- ↑ "6 Predefined Types and Classes". https://www.haskell.org/onlinereport/haskell2010/haskellch6.html#x13-1250006.1.8.
- ↑ "OCaml library : Option". https://v2.ocaml.org/releases/4.13/api/Option.html#TYPEt.
- ↑ "Option in core::option - Rust". 2022-05-18. https://doc.rust-lang.org/core/option/enum.Option.html.
- ↑ "Apple Developer Documentation". https://developer.apple.com/documentation/swift/optional.
Original source: https://en.wikipedia.org/wiki/Option type.
Read more |