Getting a Good Grasp of F# (仮)

関数型言語F#をもっと楽しみたい

F#で集合を扱う その1

F#で数学における「集合」を扱うために、名前空間Microsoft.FSharp.Collections には Set というモジュールが用意されています。

整数0から5までの集合を作るには、

let is = Set.ofList [0..5]

このコードは、整数0から5のリスト [0; 1; 2; 3; 4; 5] Set.ofList という関数を適用して集合 is を生成しています。

F# Interactiveで実行してみると

> let is = Set.ofList [0..5];;
val is : Set<int> = set [0; 1; 2; 3; 4; 5]

Set.ofList は set で代用できるので以下のコードも同じ意味。

let is = set [0..5]
> let is = set [0..5];;
val is : Set<int> = set [0; 1; 2; 3; 4; 5]

コンソール出力ではリストとの区別は分かりにくいのですが 、F#の集合(Set)は内部的に平衡二分木によって要素を保持しています。要素の重複は許可されません。順序付けのために各要素を比較する必要があるため、この集合における要素は前提条件として、型制約があり IComparable インターフェイスを実装している必要があります。普通のプリミティブ型などは特に問題なく要素として使えます。

例えば、順序を無視して要素を与えても同じ集合を生成できます。

> let is = set [1; 0; 2; 4; 3; 5];;
val is : Set<int> = set [0; 1; 2; 3; 4; 5]

リストどうしでは要素の並び順が違えば同値とはみなしませんが、

> [0; 1; 2; 3; 4; 5] = [1; 0; 2; 4; 3; 5];;
val it : bool = false

集合どうしでは要素の与え方に関わらず同値とみなします。

> set [0; 1; 2; 3; 4; 5] = set [1; 0; 2; 4; 3; 5];;
val it : bool = true

注意:上の例では、単純にイコール記号(=)を使ってリストどうしや集合どうしの同値判定をしていますが、この場合は内部的に System.Object クラスの Equals メソッドのオーバーライドが行われていて、データ構造に配慮した適切な同値判定が行われています。

集合を定義する方法は複数あり、パイプライン演算子 |> を用いて要素を1つずつ集合に追加していくこともできます。

> let s2 = 
    set []
    |> Set.add 1
    |> Set.add 0
    |> Set.add 2
    |> Set.add 4
    |> Set.add 3
    |> Set.add 5 ;;

val s2 : Set<int> = set [0; 1; 2; 3; 4; 5]

 集合において要素の重複は許可されないので、下記コードのように同じ値を何度追加しても2回目以降は要素を追加することはできません。

> let s3 =
    set []
    |> Set.add 1    
    |> Set.add 1    
    |> Set.add 1 ;; 
 
val s3 : Set<int> = set [1]