Option
In F# an option is a discriminated union. This is similar to a Nullable in C#. It can have a value (like an int
) or be None
. It is an optional int
: a value that might not exist.
Options will cause some small level of performance overhead, but if we use them to prevent exceptions, they can result in an overall improvement in F#.
Let us begin. Many built-in functions like List.tryFindIndex
return options. This function uses a predicate (a lambda) and returns the first index where an element matches.
int
. We cannot use it as an int
directly—we must extract its Value.int
to the screen, we see the type name "Some." If the inner value is 2, we see "Some 2."IsNone
and IsSome
will return true if the option is None
or is Some. Often we use these in if
-statements.None
.// An example list. let ids = [10; 20; 30] // Find index of element with value 30. // ... This returns an option int. let result = List.tryFindIndex (fun y -> y = 30) ids // Write return value. printfn "Result = %A" result printfn "IsNone = %A" result.IsNone printfn "IsSome = %A" result.IsSome // See if there is a value. if result.IsSome then // Get and write the value. let num = result.Value printfn "Value = %A" numResult = Some 2 IsNone = false IsSome = true Value = 2
None
, SomeHere we examine how to create a discriminated union (an option) from a function. In checkNumber
we receive one argument, and return None
or a Some value based on that argument.
checkNumber
, we get None
back. We test this with an if.checkNumber
and get Some number back. We use IsSome
to test it, and then print its value.// If number is 0, return None. // ... Otherwise return Some number. let checkNumber n = match n with | 0 -> None | _ -> Some(n) // This returns None. let c = checkNumber 0 if c = None then printfn "None returned" // This returns Some number. let n = checkNumber 1 if n.IsSome then printfn "Some returned, value = %A" n.ValueNone returned Some returned, value = 1
We cannot use an option as we would use the underlying value. An error will occur. We must access IsSome
and Value on the result of tryFindIndex
.
// This returns an option int, not an int. let index = List.tryFindIndex (fun y -> y = 10) [2; 10; 12] // We must access the Value, not just use the option. let result = index + 1error FS0001: The type 'int' does not match the type 'int option'
Options eliminate the need to have special values mean "no value." For example, using None
instead of -1 to mean "nothing found" may be clearer. Options help clarify our code.