サーチ…


オプションの定義

Optionは、 NoneまたはSome 2つのケースで区別されたユニオンです。

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

NULL値に対してOption <'T>を使用する

F#ような関数型プログラミング言語では、値は潜在的に有害で貧弱なスタイル(非慣用的)とみなされnull

このC#コードを考えてみましょう:

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

xnull場合はx.Lengthがスローされnull保護を追加しましょう:

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

または:

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

または:

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

慣用句F# null値は使用されないので、コードは次のようになります。

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

ただし、空の値または無効な値を表す必要があることがあります。それから、 Option<'T>使うことができます:

let SomeFunction () : string option = ...

SomeFunctionは、 Some string値またはNone返します。パターンマッチングを用いてstring値を抽出する

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

このコードが以下の理由より脆弱でない理由は:

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

string option Lengthを呼び出すことができないからです。パターンマッチングを使用してstring値を抽出する必要があります。そうすることで、 string値が安全に使用できることが保証されます。

オプションモジュールにより鉄道指向プログラミングが可能

エラー処理は重要ですが、優雅なアルゴリズムを混乱させる可能性があります。 鉄道指向プログラミングROP )は、エラー処理をエレガントで構成可能にするために使用されます。

簡単な関数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

目的f 、入力解析するstring (存在する場合は値をSome )にintint0より大きい場合は、 floatキャストします。それ以外の場合は、「 None 」で救済する。

ただし、ネストされたmatchが非常に単純な関数では、可読性が大幅に低下します。

ROPはプログラムで2種類の実行パスがあることを確認しています

  1. ハッピーパス-最終的に計算しますSome値を
  2. エラーパス-他のすべてのパスは発生しないNone

エラー・パスは頻繁に発生するため、コードを引き継ぐ傾向があります。ハッピーなパスコードが最も目に見えるコードパスであることを望みます。

ROPを使った同等の関数g 、次のようになります。

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

F#でリストやシーケンスを処理する傾向によく似ています。

一つは、見ることができるOption<'T>のようなList<'T>のみ含まれていてもよい0または1の要素Option.bind同じように動作しList.pick (概念的Option.bindより良いにマップをList.collectが、 List.pickあるかもしれません理解しやすい)。

bindfilter 、およびmapはエラー・パスを処理し、 gはハッピー・パス・コードのみを処理します。

直接受け入れるすべての機能Option<_>と返すOption<_>との直接構成可能です|>>>

したがってROPは可読性と合成性を向上させます。

C#のオプションタイプを使用する

Option型をC#コードに公開するのは良い考えではありません.C#にはそれらを処理する方法がないからです。オプションは、C#プロジェクトの依存関係としてFSharp.Coreを導入するか(C#との相互運用用に設計されていない F#ライブラリを使用している場合に必要な作業です)、またはNone値をnullに変更しnull

Pre-F#4.0

これを行う方法は、あなた自身の変換関数を作成することです:

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

値の型は、ボクシングやSystem.Nullableを使用する必要があります。

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

F#4.0

F#4.0では、 Optionモジュールに導入されたofObjtoObjofNullable 、およびtoNullableが使用されています。 F#インタラクティブでは、次のように使用できます。

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

None内部的にnullコンパイルされることに注意してください。しかし、F#に関する限り、それは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
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow