Buscar..


Definición de Opción

Una Option es una unión discriminada con dos casos, None o Some .

type Option<'T> = Some of 'T | None

Utilice la opción <'T> sobre valores nulos

En los lenguajes de programación funcional, como F# null valores null se consideran potencialmente dañinos y de estilo deficiente (no idiomático).

Considere este código C# :

string x = SomeFunction ();
int    l = x.Length;

x.Length lanzará si x es null , agreguemos protección:

string x = SomeFunction ();
int    l = x != null ? x.Length : 0;

O:

string x = SomeFunction () ?? "";
int    l = x.Length;

O:

string x = SomeFunction ();
int    l = x?.Length;

En null valores null F# idiomáticos no se utilizan, por lo que nuestro código se ve así:

let x = SomeFunction ()
let l = x.Length

Sin embargo, a veces es necesario representar valores vacíos o no válidos. Entonces podemos usar la Option<'T> :

let SomeFunction () : string option = ...

SomeFunction devuelve Some valor de string o None . Extraemos el valor de la string utilizando el patrón de coincidencia

let v =
  match SomeFunction () with
  | Some x  -> x.Length
  | None    -> 0

La razón por la cual este código es menos frágil que:

string x = SomeFunction ();
int    l = x.Length;

Es porque no podemos llamar Length en una string option . Necesitamos extraer el valor de la string utilizando la coincidencia de patrones y al hacerlo, tenemos la garantía de que el valor de la string es seguro de usar.

El módulo opcional habilita la programación orientada al ferrocarril

El manejo de errores es importante pero puede convertir un algoritmo elegante en un desastre. La Programación Orientada a Ferrocarriles ( ROP ) se utiliza para hacer que el manejo de errores sea elegante y componible.

Considere la función simple f :

let tryParse s =
  let b, v = System.Int32.TryParse s
  if b then Some v else None

let f (g : string option) : float option =
  match g with
  | None    -> None
  | Some s  ->
    match tryParse s with           // Parses string to int
    | None              -> None
    | Some v when v < 0 -> None     // Checks that int is greater than 0
    | Some v -> v |> float |> Some  // Maps int to float

El propósito de f es analizar el valor de la string entrada (si hay Some ) en un int . Si el int es mayor que 0 lanzamos en un float . En todos los demás casos, rescatamos con None .

Aunque es una función extremadamente simple, la match anidada disminuye significativamente la legibilidad.

ROP observa que tenemos dos tipos de vías de ejecución en nuestro programa

  1. Camino feliz - eventualmente calcularemos Some valor
  2. Ruta de error: todas las demás rutas producen None

Como las rutas de error son más frecuentes, tienden a tomar el control del código. Nos gustaría que el código de ruta feliz sea la ruta de código más visible.

Una función equivalente g usa ROP podría verse así:

let g (v : string option) : float option =
  v
  |> Option.bind    tryParse  // Parses string to int
  |> Option.filter  ((<) 0)   // Checks that int is greater than 0
  |> Option.map     float     // Maps int to float

Se parece mucho a cómo tendemos a procesar listas y secuencias en F# .

Uno puede ver una Option<'T> como una List<'T> que solo puede contener 0 o 1 elemento donde Option.bind comporta como List.pick (conceptualmente Option.bind asigna mejor a List.collect pero List.pick podría ser Más fácil de entender).

bind , filter y map manejan las rutas de error g solo contienen el código de ruta feliz.

Todas las funciones que aceptan directamente la Option<_> y devuelven la Option<_> pueden componer directamente con |> y >> .

ROP por lo tanto aumenta la legibilidad y la composibilidad.

Usando tipos de opciones de C #

No es una buena idea exponer los tipos de opción al código C #, ya que C # no tiene una forma de manejarlos. Las opciones son introducir FSharp.Core como una dependencia en su proyecto de C # (que es lo que tendría que hacer si está consumiendo una biblioteca de F # no diseñada para interoperar con C #), o cambiar los valores de None a null .

Pre-F # 4.0

La forma de hacerlo es crear una función de conversión propia:

let OptionToObject opt =
    match opt with
    | Some x -> x 
    | None -> null

Para los tipos de valor tendría que recurrir a boxearlos o usar System.Nullable .

let OptionToNullable x = 
    match x with 
    | Some i -> System.Nullable i
    | None -> System.Nullable ()

F # 4.0

En F # 4.0, las funciones ofObj , toObj , ofNullable y toNullable introdujeron en el módulo de Option . En F # interactivo se pueden utilizar de la siguiente manera:

let l1 = [ Some 1 ; None ; Some 2]
let l2 = l1 |> List.map Option.toNullable;;

// val l1 : int option list = [Some 1; null; Some 2]
// val l2 : System.Nullable<int> list = [1; null; 2]

let l3 = l2 |> List.map Option.ofNullable;;
// val l3 : int option list = [Some 1; null; Some 2]

// Equality
l1 = l2 // fails to compile: different types
l1 = l3 // true

Tenga en cuenta que None compila a null internamente. Sin embargo, en lo que respecta a F #, es un None .

let lA = [Some "a"; None; Some "b"]
let lB = lA |> List.map Option.toObj

// val lA : string option list = [Some "a"; null; Some "b"]
// val lB : string list = ["a"; null; "b"]

let lC = lB |> List.map Option.ofObj
// val lC : string option list = [Some "a"; null; Some "b"]

// Equality
lA = lB // fails to compile: different types
lA = lC // true


Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow