F# タプルの拡張メソッドを作成することはできますか? たとえば、インスタンス メソッド .Item1 および .Item2 (System.Tuple など) を追加するには、2 タプルに対して fst および snd を呼び出すのと同等ですか?
5 に答える
F# で (2 要素のSystem.Tuple<'T1, 'T2>
) タプルを内部的に表す型には、実際には既にプロパティItem1
とItem2
がありますが、これらは F# コンパイラによって隠されています。拡張メンバーをタプルに追加する明白な方法ではうまくいかないので、これがうまくいくとは思いません (しかし、私が知らない回避策があるかもしれません)。
Item1
一般に、パターン マッチングは などのメンバーよりも好ましいと思いますItem2
(また、C# 3.0 プログラマーは、タプルを操作するときにパターン マッチングのサポートを求めることがよくあります :-))。
その理由は、パターン マッチングでは名前を付ける必要があるからです。次の 2 つのコード スニペットを比較します。
let (width, height) = tuple
width * height
およびプロパティを使用するバージョン:
tuple.Item1 * tuple.Item2
2 番目は少し短いですが、明らかに読みにくくなっています。
完璧ではありませんが、私はこれを使用しています。( http://www.fssnip.net/6Vから元のコードを借りて、小さな変更を加えました。)
[<AutoOpen>]
module TupleExtensions =
type System.Tuple with
static member Item1(t) = let (x,_) = t in x
static member Item1(t) = let (x,_,_) = t in x
static member Item1(t) = let (x,_,_,_) = t in x
static member Item1(t) = let (x,_,_,_,_) = t in x
static member Item1(t) = let (x,_,_,_,_,_) = t in x
static member Item1(t) = let (x,_,_,_,_,_,_) = t in x
static member Item2(t) = let (_,x) = t in x
static member Item2(t) = let (_,x,_) = t in x
static member Item2(t) = let (_,x,_,_) = t in x
static member Item2(t) = let (_,x,_,_,_) = t in x
static member Item2(t) = let (_,x,_,_,_,_) = t in x
static member Item2(t) = let (_,x,_,_,_,_,_) = t in x
static member Item3(t) = let (_,_,x) = t in x
static member Item3(t) = let (_,_,x,_) = t in x
static member Item3(t) = let (_,_,x,_,_) = t in x
static member Item3(t) = let (_,_,x,_,_,_) = t in x
static member Item3(t) = let (_,_,x,_,_,_,_) = t in x
static member Item4(t) = let (_,_,_,x) = t in x
static member Item4(t) = let (_,_,_,x,_) = t in x
static member Item4(t) = let (_,_,_,x,_,_) = t in x
static member Item4(t) = let (_,_,_,x,_,_,_) = t in x
static member Item5(t) = let (_,_,_,_,x) = t in x
static member Item5(t) = let (_,_,_,_,x,_) = t in x
static member Item5(t) = let (_,_,_,_,x,_,_) = t in x
static member Item6(t) = let (_,_,_,_,_,x) = t in x
static member Item6(t) = let (_,_,_,_,_,x,_) = t in x
static member Item7(t) = let (_,_,_,_,_,_,x) = t in x
それの使い方:
let t = (1, 2, 3)
let item1 = Tuple.Item1(t)
ここで定義されている Tuple.Item1 は、fst よりも優れています。項目数に対して多態的です。これらの拡張メソッドを使用して n タプルを使用する関数を作成すると、関数本体を変更せずに n+1 タプルに拡張できます。代わりに、引数の型宣言を変更する必要があります。それはより楽です。
fst
および関数を使用してsnd
、必要な値を取得することもできます (実際に必要な場合は、明らかに 3 番目、4 番目などに独自の値を記述します)。
あなたが求めているのは、あまり機能的な方法ではないと思います。インスタンス メソッドを使用して独自の型を作成できますが、同時に、パターン マッチングなど、関数型プログラミングの多くの側面が失われます。
それ以外は、DU が適しているようです。
type MyTuple<'T, 'U> =
| MyTuple of 'T * 'U
with
member this.MyItem1 = match this with | MyTuple(x,y) -> x
member this.MyItem2 = match this with | MyTuple(x,y) -> y
let x = MyTuple(42, "foo")
let y1 = x.MyItem1 // 42
let y2 = x.MyItem2 // "foo"
@Tomas Petricek が指摘したように、プロパティItem1
に名前を付けることはできません。Item2
それらは既に に存在するためSystem.Tuple<'T1, 'T2>
です。これを行おうとすると、エラーが発生します。
エラー FS2014: バイナリ [ファイル名] の書き込みで問題が発生しました: 型 [...] の pass2 でエラーが発生しました。エラー: 型 MyTuple`2 の pass2 でエラーが発生しました。エラー: プロパティ テーブルにエントリ 'Item1' が重複しています