2017-09-29 5 views
1

私は、.NETリストタイプ(例えばIList<>List<>)のパターンマッチングを試してみました:任意の.NETタイプ/インタフェースをリストとしてパターンマッチングできますか?

match myIList with 
| [] -> ... 

私はThe expression was expected to have type IList<...> but here has type 'a listを言ってエラーを得ました。私はそれがうまくいかない理由を知っている - 明らかに、型は互換性がない(私はF#のリスト型がIList<>を実装していないと推測するだろう)。

match式のSeq.toListをスローしなくても、パターンマッチングできるBCLリストタイプはありますか?

答えて

3

いいえ、F#リストの構築と分解に使用される構文は、その型とその型に対してのみ定義されます(これらの演算子は実際にはlistのケースラベルとして使用され、コンパイラから特別な扱いを受けます)。

type List<'T> = 
    | ([]) :     'T list 
    | (::) : Head: 'T * Tail: 'T list -> 'T list 

F#のリストがSystem.Collections.Generic.Listとは根本的に異なっている - それはcons listだし、このような性質は、建設/解体するための構文に反映されます。これは、リストタイプはコアライブラリで定義されている方法です。

System.Collections.Generic.Listは、サイズが大きくなる可能性がありますが、配列のバッキングで配列のパフォーマンス特性を持つコレクションです。実際はF#の名前(ResizeArray)がはるかに適しています。

IListは変更可能なリストのインターフェイスですが、F#リストは不変です。IListを実装するのは意味がありません。

これらの両方のタイプの場合、F#リストに対して行われたのと同じ方法で頭と尾に分解すると、単純にその現実が反映されず、不自然な操作になりますF#リストへのインデックス付けは不自然な操作です)。

1

BCLから、私は、配列は、C#が行うようhttps://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/pattern-matching#array-pattern

let vectorLength vec = 
    match vec with 
    | [| var1 |] -> var1 
    | [| var1; var2 |] -> sqrt (var1*var1 + var2*var2) 
    | [| var1; var2; var3 |] -> sqrt (var1*var1 + var2*var2 + var3*var3) 
    | _ -> failwith "vectorLength called with an unsupported array size of %d." (vec.Length) 

printfn "%f" (vectorLength [| 1. |]) 
printfn "%f" (vectorLength [| 1.; 1. |]) 
printfn "%f" (vectorLength [| 1.; 1.; 1.; |]) 
printfn "%f" (vectorLength [| |]) 
3

F#は、自動型変換を行いませんを参照してくださいSeq.toList

を必要とせずに一致させることができる唯一のコレクション型であると信じています。つまり、異なる型の2つの値を比較することはできません。たとえその一方が他方の型のサブタイプであっても比較することはできません。あなたの特定のケースにこれを適用する

let x : string = "abc" 
let y : obj = box "abc" 
let eq = x = y // Type mismatch error here 

、あなたはその値が何らかの形で、リストのサブタイプであっても、リスト上の非リストの値と一致することはできません。

let (|IsList|) l = Seq.toList l 
:あなたは、マッチングのこの種では本当に興味があるなら

しかし、あなた自身seq<'t>を取ると、通常のF#のリストとそれにマッチします(また、「active pattern」として知られている)、カスタム照合を、書くことができます

このようなマッチャがseqことができるものと使用可能です - でも、例えば、文字列:あまりにも通常のリストの

match "abcd" with 
| IsList [] -> "Empty string" 
| IsList ('a'::_) -> "Starts with an a" 
| IsList _ -> "Something else" 

ワークス:

match [1,2,3] with 
| IsList [1,2,3] -> "One, two, three" 
| IsList [] -> "Empty list" 
| IsList _ -> "Huh?" 
関連する問題