41

私が知っているOCamlプログラマーの中には、常にポリモーフィックバリアント(宣言されていない、バッククォートが前に付いているバリアント)を使用するものもあれば、ポリモーフィックバリアントを使用せ、型で宣言されたバリアントを好むものもあることに気付きました。

パフォーマンス上の理由(ポリモーフィックバリアントは現在、単純なバリアントよりも効率が低い)を除いて、専門家のOCaml開発者はどのようにそれらから選択しますか?

4

3 に答える 3

43

私の使い方は以下の5つに分類できます。1. インターフェイス 2. モジュール性 3. 読みやすさ 4. 簡潔さ 5. トリック

  1. バリアント型がモジュールの内部にのみある場合は、通常のバリアントを使用します。これは、あなたが言ったように、より効率的にコンパイルされるためです。
  2. バリアント型がインターフェイスでエクスポートされ、一部のケースが他のモジュールに表示される可能性があるが、それらをモジュールに依存させることが必ずしも意味をなさないと感じた場合、モジュールの名前空間システムに関連付けられていないため、ポリモーフィック バリアントを使用します。 . 例: のエンコーディング タイプtype Xmlm. また、シグナル型をバリアント型として持つということは、.xml への依存関係を導入することなく、XML 処理に同じ考え方を使用してモジュールを開発できることを意味しますXmlm
  3. バリアント型がインターフェイスでエクスポートされている場合、バリアント型の値がモジュールの関数に与えられている場合、通常のバリアントを使用するには冗長すぎる場合があります。例: のバージョンタイプUuidm。書く必要がある代わりに、Uuidm.create Uuidm.V4単純に書くことができますUuidm.create `V4。これは明確で冗長ではありません。
  4. 特定の関数が異なるケースを返す場合があります。これらのケースがこの関数でのみ使用される場合は、型定義を導入することなく、インターフェイスで関数型を宣言します。例えばparse : string -> [`Error of string | `Ok of t]
  5. ポリモーフィック バリアントとそのサブタイピングにより、ファントム型で不変条件を静的に適用できます。それらを段階的に定義する可能性に加えて、不変条件を静的に強制する場合とドキュメント化する場合の両方に役立ちます。

最後に、4. に従ってモジュールの実装にポリモーフィック バリアントを使用することがありますが、それらはインターフェイスに表示されません。ポリモーフィック バリアントを宣言して閉じない限り、この使用法はお勧めしません。静的型付けの規律が弱まるからです。

于 2012-02-20T20:13:24.220 に答える
17

ほとんどのモジュールインターフェイスでポリモーフィックバリアントを使用する唯一の理由は、クラシックバリアントの命名の問題を回避するためです。

以下が機能する場合、ほとんどの場合、多形バリアントは役に立たなくなります。

タイプt1=文字列の文字列| Int of int | ブールのブール| t1リストのリスト
タイプt2=文字列の文字列| Int of int | 他の

x=を単純化しましょう
  (x:t1)と一致する
      文字列s->文字列s
    | Int n-> Int n
    | ブール_
    | リスト_->その他

2014-02-21更新:上記のコードはOCaml4.01で有効になりました。やあ!

于 2012-02-20T19:55:41.370 に答える
13

ポリモーフィック バリアントの効率が常に低いというのは事実ではありません。Martin の例を使用すると、次のようになります。

type base = [`String of string | `Int of int]
type t1 = [base | `Bool of bool | `List of t1 list]
type t2 = [base | `Other]

let simplify (x:t1):t2 = match x with
| #base as b -> b
| `Bool _ | `List _ -> `Other

標準バリアントでこれを行うには、2 つの異なる型と完全な再コーディングが必要です。ポリモーフィック バリアントでは、ベース ケースは物理的に不変です。この機能は、用語の書き換えにオープン再帰を使用する場合に真価を発揮します。

type leaf = [`String of string | `Int of int]
type 'b base = [leaf | `List of 'b list]
type t1 = [t1 base | `Bool of bool ]
type t2 = [t2 base | `Other]

let rec simplify (x:t1):t2 = match x with
| #leaf as x -> x
| `List t -> `List (List.map simplify t)
| `Bool _ -> `Other

また、書き換え関数もオープン再帰で因数分解すると、利点はさらに大きくなります。

残念ながら、Ocaml の Hindley-Milner 型推論は、明示的な型付けを行わない限り、この種のことを行うには十分強力ではありません。型を慎重に因数分解する必要があり、プロトタイプ作成が困難になります。さらに、明示的な強制が必要になる場合もあります。

この手法の大きな欠点は、複数のパラメーターを持つ用語の場合、型の組み合わせがかなり混乱する結果になり、最終的には静的な強制をあきらめて、ワイルドカードと例外を使用したキッチン シンク型を使用する方が簡単になることです。 (つまり、動的型付け)。

于 2012-02-26T19:05:02.577 に答える