2011-12-21 4 views
13

タプル内のアイテムには名前がありません。つまり、各アイテムの意味を明確に文書化することはできません。例えば型のエイリアスを使用してパラメータの意味を示すのが標準的な方法ですか?

、この中で労働組合を区別:

type NetworkEvent = 
| Message of string * string * string 
| ... 

は、私はそれを明確に第一及び第二の項目は、それぞれ送信者と受信者の名前であることを確認します。このような何かをすることをお勧めし:

type SenderName = string 
type RecipientName = string 

type NetworkEvent = 
| Message of SenderName * RecipientName * string 
| ... 

C/C++ライブラリの多くは、パラメータ名は、多くの場合、オプションであっても、型の増殖(例えばwin32.hを)しているが、それらの言語でそれでもやり遂げることができます。 F#の場合はそうではありません。

+3

F#3.1では、これらのフィールドに名前を付けることができます。 –

+0

@JamesMooreええ、それは私を幸せにします:D –

答えて

10

type NetworkEvent2 = 
    | UDPMessage of string * string * string 
    | Broadcast of string * string * string 
    | Loopback of string * string * string 
    | ConnectionRequest of string 
    | FlushEventQueue 

私は文書化のため型の別名を使用すると、あなたの判別組合を文書化するには良いと簡単な方法だと思います。私は多くのデモで同じアプローチを使用しています(for example this one参照)、私は一部の人が本番アプリケーションでも同じ方法を使用していることを知っています。

タイプエイリアスを使用する:この方法では、IntelliSenseに表示されるドキュメントを追加しますが、タイプシステムには伝播しません。エイリアス化された型の値を使用した場合、コンパイラはそれをstringとして扱いますので、どこにでも追加のドキュメントは表示されません。

単一ケースのユニオンを使用これは、F#コンパイラのいくつかの場所で使用されているパターンです。タイプSenderNamestring異なるタイプ実際にので(一方は、これはいくつかの小さなパフォーマンスペナルティを有していてもよい)、型エイリアスを使用するよりも可視情報を行います

type SenderName = SenderName of string 
type RecipientName = RecipientName of string 
type NetworkElement = 
    | Message of SenderName * RecipietName * string 

match netelem with 
| Message(SenderName sender, RecipientName recipiet, msg) -> ... 

使用レコード:このようにして、ユニオンケースの情報を保持するレコードを明示的に定義します。これは構文的には冗長ですが、おそらく最もアクセスしやすい方法で追加情報が追加される可能性があります。レコードでパターンマッチングを使用することも、ドット表記を使用して要素にアクセスすることもできます。開発中に新しいフィールドを追加する方が簡単です。

type MessageData = 
    { SenderName : string; RecipientName : string; Message : string } 
type NetworkEvent = 
    | Message of MessageData 

match netelem with 
| Message{ SenderName = sender; RecipientName = recipiet; Message = msg} -> ... 
+3

これはおそらく少数派の見解ですが、レコードやシングルケースのユニオンの冗長性は私のマインド。それは、組合の簡潔さ/構文上の利便性を完全に否定する。これは、Intellisenseが解決した問題のように思えます。フィールドに注釈を付ける方法があれば、型やコーディングスタイルは変わりません。 – Daniel

+1

私はこの(そうでなければ優れた)答えが更新を必要とするかもしれないと思います。これで 'type X = Msg of Sender:string * Recip:string'を実行できます。 'let x = X(Sender =" Foo "、Recip =" Bar ")'これらのフィールドも使えます。レコードと似ていますが、構文は異なります。 – Abel

1

私はこの場合、タプルの最初の2つの要素にレコード型を使用する方が、その順序が重要であるという事実を強調する方が良いでしょう。番号については

、あなたが測定単位を使用してもう少しエレガントな何かを行うことができますが、これは、文字列

+0

レコードの拡散は悪くないでしょうか?悪くない場合は、たくさんの「NetworkEvents」があるでしょうか?類似したパラメータ名を持つレコードがたくさんある場合、型推論は本当に混乱し、すべての単一フィールドを完全修飾する必要があります。 –

+0

@ReiMiyasaka - 実際に状況はそれほど悪くはありません。レコードをインスタンス化する際に言及した最初のフィールドを完全に修飾すると、他のフィールドは正しく解決されます。 – Kit

1

のために動作しません。私はこれに何か問題が表示されていないが、それはのための10件のエイリアスを迷惑持ってしまうかもしれません例えば、である。それがあなたを気にしないならば、私は言う。個人的に、私は次のようなものがサポートされていた希望:

type NetworkEvent = 
| Message of SenderName:string * RecipientName:string * string 
| ... 

その後、インテリセンスはいくつかの助けを提供することができます。 (編集:この提案に投票するhere

ケースにフィールドが複数あるか、同じタイプが複数ある場合は、代わりにクラス階層を使用することを検討してください。

+0

ええ、F#の文法には、C#と同じくらい豊富なIntelliSenseを持つことは不可能です。 –

+0

最近、F-3.1では、個々のフィールドに名前を付けることができますが、同じケース内の他のフィールドに名前が付けられていても名前はオプションです。 http://msdn.microsoft.com/en-us/library/dd233226.aspx –

6

私はインターネットと本の両方でF#の私の分担金を読んだことがありますが、ドキュメントの形式としてエイリアスを使用したことは一度もありません。だから私はそれが標準的な練習ではないと言うつもりです。また、コードの重複の一種とみなすこともできます。

一般に、特定のタプル表現は、関数内の一時データ構造としてのみ使用する必要があります。長い時間タプルを保管している場合や、異なるクラス間でタプルを渡している場合は、レコードを作成します。

差別化された共用体を複数のクラスにわたって使用する場合は、示唆したようにレコードを使用するか、以下のようにすべてのメソッドのスコープを区別したユニオンに限定します。

type NetworkEvent = 
    | Message of string * string * string 

    static member Create(sender, recipient, message) = 
     Message(sender, recipient, message) 

    member this.Send() = 
     math this with 
     | Message(sender, recipient, message) -> 
      printf "Sent: %A" message 

let message = NetworkEvent.Create("me", "you", "hi") 

タプルは本当に利便性の問題であり、コードが大きくなるにつれて、レコードに置き換えられる必要がありますので、あなたは、records in pattern matchingを使用することができます。

差別化された組合に同じ署名のタプルがある場合は、それを2つの区別された組合に分解する時期です。これにより、同じ署名を持つ複数のレコードを持つこともできなくなります。

type MessageType = 
    | UDPMessage 
    | Broadcast 
    | Loopback 

type NetworkEvent = 
    | Message of MessageType * string * string * string 
    | ConnectionRequest of string 
    | FlushEventQueue 
関連する問題