サーチ…
差別化された共用体内のタプルの要素の命名
識別された共用体を定義するときには、タプル型の要素に名前を付け、パターンマッチングの際にこれらの名前を使用できます。
type Shape =
| Circle of diameter:int
| Rectangle of width:int * height:int
let shapeIsTenWide = function
| Circle(diameter=10)
| Rectangle(width=10) -> true
| _ -> false
さらに、識別された共用体の要素に名前を付けることで、コードの可読性が向上し、C#で提供される名前との相互運用性がプロパティの名前とコンストラクタのパラメータに使用されます。 interopコードで生成されるデフォルトの名前は "Item"、 "Item1"、 "Item2" ...
差別化された連合使用の基本
F#の差別化された組合は、任意の数の異なるデータ型を保持できる型を定義する方法を提供します。それらの機能は、C ++のユニオンやVBのバリアントに似ていますが、タイプセーフであるという追加の利点があります。
// define a discriminated union that can hold either a float or a string
type numOrString =
| F of float
| S of string
let str = S "hi" // use the S constructor to create a string
let fl = F 3.5 // use the F constructor to create a float
// you can use pattern matching to deconstruct each type
let whatType x =
match x with
| F f -> printfn "%f is a float" f
| S s -> printfn "%s is a string" s
whatType str // hi is a string
whatType fl // 3.500000 is a float
列挙型のユニオン
差別化された組合の場合には、タイプ情報を含める必要はありません。型情報を省略することで、列挙型に似た一連の選択肢を単純に表すユニオンを作成できます。
// This union can represent any one day of the week but none of
// them are tied to a specific underlying F# type
type DayOfWeek = Monday | Tuesday | Wednesday | Thursday | Friday | Saturday | Sunday
反射を伴う文字列への変換
Discriminated Unionを文字列との間で変換する必要がある場合があります。
module UnionConversion
open Microsoft.FSharp.Reflection
let toString (x: 'a) =
match FSharpValue.GetUnionFields(x, typeof<'a>) with
| case, _ -> case.Name
let fromString<'a> (s : string) =
match FSharpType.GetUnionCases typeof<'a> |> Array.filter (fun case -> case.Name = s) with
| [|case|] -> Some(FSharpValue.MakeUnion(case, [||])) :?> 'a)
| _ -> None
シングルケースの識別ユニオン
単一のケース識別されたユニオンは、それが1つのケースのみを有することを除いて、他の識別されたユニオンと同様である。
// Define single-case discriminated union type.
type OrderId = OrderId of int
// Construct OrderId type.
let order = OrderId 123
// Deconstruct using pattern matching.
// Parentheses used so compiler doesn't think it is a function definition.
let (OrderId id) = order
これは、型の安全性を強化するのに便利で、C#やJavaではなく、新しい型を作成するとオーバーヘッドが増えますが、F#ではよく使用されます。
次の2つの代替型定義によって、同じ単一ケースの識別された共用体が宣言されます。
type OrderId = | OrderId of int
type OrderId =
| OrderId of int
単一のケースで識別された共用体をレコードとして使用する
レコードのような型を実装するために、1つのケースのみで共用体の型を作成すると便利な場合があります。
type Point = Point of float * float
let point1 = Point(0.0, 3.0)
let point2 = Point(-2.5, -4.0)
これらは、タプル引数と同じ方法でパターンマッチングによって分解できるので、非常に便利になります。
let (Point(x1, y1)) = point1
// val x1 : float = 0.0
// val y1 : float = 3.0
let distance (Point(x1,y1)) (Point(x2,y2)) =
pown (x2-x1) 2 + pown (y2-y1) 2 |> sqrt
// val distance : Point -> Point -> float
distance point1 point2
// val it : float = 7.433034374
RequireQualifiedAccess
RequireQualifiedAccess
属性、組合の例は、と呼ばれなければならないMyUnion.MyCase
だけではなくMyCase
。これは、囲み名前空間またはモジュールの名前の衝突を防ぎます:
type [<RequireQualifiedAccess>] Requirements =
None | Single | All
// Uses the DU with qualified access
let noRequirements = Requirements.None
// Here, None still refers to the standard F# option case
let getNothing () = None
// Compiler error unless All has been defined elsewhere
let invalid = All
たとえば、 System
が開かれている場合、 Single
はSystem.Single
参照しSystem.Single
。ユニオンケースのRequirements.Single
との衝突はありません。
再帰的な差別化された組合
再帰型
差別化された組合は、再帰的である可能性があります。つまり、それらの定義で自分自身を参照することができます。ここで最も重要な例はツリーです。
type Tree =
| Branch of int * Tree list
| Leaf of int
例として、次のツリーを定義しましょう:
1
2 5
3 4
再帰的に識別された共用体を使用して、このツリーを次のように定義できます。
let leaf1 = Leaf 3
let leaf2 = Leaf 4
let leaf3 = Leaf 5
let branch1 = Branch (2, [leaf1; leaf2])
let tip = Branch (1, [branch1; leaf3])
ツリーを反復することは、パターンマッチングの問題です。
let rec toList tree =
match tree with
| Leaf x -> [x]
| Branch (x, xs) -> x :: (List.collect toList xs)
let treeAsList = toList tip // [1; 2; 3; 4; 5]
相互に依存する再帰型
再帰を達成する1つの方法は、相互に依存する型を入れ子にすることです。
// BAD
type Arithmetic = {left: Expression; op:string; right: Expression}
// illegal because until this point, Expression is undefined
type Expression =
| LiteralExpr of obj
| ArithmeticExpr of Arithmetic
区別された共用体の中に直接レコード型を定義することは推奨されません。
// BAD
type Expression =
| LiteralExpr of obj
| ArithmeticExpr of {left: Expression; op:string; right: Expression}
// illegal in recent F# versions
相互に依存する定義を連鎖させるには、 and
キーワードを使用できます。
// GOOD
type Arithmetic = {left: Expression; op:string; right: Expression}
and Expression =
| LiteralExpr of obj
| ArithmeticExpr of Arithmetic