Sök…


Definition av alternativ

Ett Option är en diskriminerad union med två fall, None eller Some .

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

Använd alternativ <'T> över nollvärden

I funktionella programmeringsspråk som F# null värden anses vara potentiellt skadlig och dålig stil (icke-idiomatisk).

Tänk på denna C# -kod:

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

x.Length kommer att kasta om x är null låt oss lägga till skydd:

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

Eller:

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

Eller:

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

I idiomatiska F# null används inte så vår kod ser så här ut:

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

Ibland finns det emellertid ett behov av att representera tomma eller ogiltiga värden. Då kan vi använda Option<'T> :

let SomeFunction () : string option = ...

SomeFunction returnerar antingen Some string eller None . Vi extraherar string med mönstermatchning

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

Anledningen till att denna kod är mindre ömtålig än:

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

Det beror på att vi inte kan kalla Length på ett string option . Vi måste extrahera string hjälp av mönstermatchning och genom att göra det är vi garanterade att string är säkert att använda.

Alternativmodul möjliggör järnvägsorienterad programmering

Felhantering är viktigt men kan göra en elegant algoritm till en röra. Järnvägsorienterad programmering ( ROP ) används för att göra felhantering elegant och komponerbar.

Tänk på den enkla funktionen 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

Syftet med f är att tolka den ingående string värde (om det finns Some ) i en int . Om int är större än 0 kastar vi det i en float . I alla andra fall räddar vi ut med None .

Även en extremt enkel funktion minskar den kapslade match läsbarheten avsevärt.

ROP konstaterar att vi har två slags exekveringsvägar i vårt program

  1. Lycklig väg - Beräknar så småningom Some värde
  2. Felväg - Alla andra sökvägar producerar None

Eftersom felvägarna är vanligare tenderar de att ta över koden. Vi vill att den lyckliga sökkoden är den mest synliga kodvägen.

En ekvivalent funktion g med ROP kan se ut så här:

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

Det ser mycket ut som hur vi tenderar att bearbeta listor och sekvenser i F# .

Man kan se ett Option<'T> som en List<'T> som bara kan innehålla 0 eller 1 element där Option.bind beter sig som List.pick (begreppsmässigt Option.bind bättre till List.collect men List.pick kan vara lättare att förstå).

bind , filter och map hanterar felvägarna och g innehåller bara den lyckliga sökkoden.

Alla funktioner som direkt accepterar Option<_> och returnerar Option<_> är direkt komponerbara med |> och >> .

ROP ökar därför läsbarheten och kompositionen.

Använda alternativstyper från C #

Det är inte bra att utsätta alternativstyper för C # -kod, eftersom C # inte har ett sätt att hantera dem. Alternativen är antingen att introducera FSharp.Core som ett beroende i ditt C # -projekt (vilket du måste göra om du konsumerar ett F # -bibliotek som inte är designat för interop med C #), eller att ändra None värden till null .

Pre-F # 4.0

Så här gör du är att skapa en egen konverteringsfunktion:

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

För värdetyper måste du använda boxning eller använda System.Nullable .

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

F # 4.0

I F # 4.0 ofObj funktionerna för ofObj , toObj , ofNullable och toNullable till Option modulen. I F # interaktiva kan de användas enligt följande:

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

Observera att None kompilerar till null internt. Men när det gäller F # är det 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
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow