3

いくつかのタイプがあります

data Foo = Foo
data Bar = Bar 
data Baz = Baz

それらをマップのキーとして使用したい。これは可能ですか?

以下の追加のコンテキスト:

VM を構築するアプリケーションがあります。作業をフェーズに分けました。現在、私はこのタイプを持っています

data CurrentPhase = PHASEONE
                  | PHASETWO
                  | PHASETHREE (deriving Eq,Ord)

これまでのところ、上記のような問題はありません。ただし、フェーズ固有の操作を記述する型クラスを作成しました

class PhaseOps phase where
  preValidate :: JobID -> phase -> Handler (Status)
  doPreProc :: JobID -> phase -> Handler (Status)
  updateConfig :: JobID -> phase -> Handler ()
  postValidate :: JobID -> phase -> Handler (Status)

これを機能させるには、インスタンスに使用するシングルトン データ型の新しいセットを作成する必要がありましたPhaseOps

data PhaseOne = PhaseOne

.. 等々

今、私はこれらのシングルトン型を持っていますCurrentPhase. 私は(キーCurrentPhaseであるマップに使用している)を取り除き、シングルトンデータ型を使用したいと思います。CurrentPhase

4

1 に答える 1

4

簡単な解決策は、 type のキーを使用することですEither Foo (Either Bar Baz)。これは、可能なタイプを追加するとすぐに冗長になり、とにかく少し醜いので、次のような専用の同等のものを使用する方が理にかなっています。

data FooBarBaz = FooVal Foo | BarVal Bar | BazVal Baz

これは、それらを 1 つの型に直接結合するのと似ていますが、個々の型を別の場所で引き続き使用できるようにするために、結合された型の冗長性が少し高くなります。これは比較的一般的なパターンです。たとえば、構文ツリーを表す型でよく見かけます。「最上位の宣言」型がこの形式を取り、各種類の宣言が独自の個別の型である場合があります。

問題の性質によっては、より良い他のアプローチがあるかもしれませんが、上記は私が考えることができる唯一の優れた汎用ソリューションです。この方法が気に入らない場合は、理由をより明確に指定し、これらのタイプを達成するために必要なことをいくらか詳しく説明してください。


明確化に応じて編集:

質問のコメントで述べたようにPhaseOps、代わりに関数の記録になりたいクラスのように見えます。さらに、そのようなクラスがある場合、複数のインスタンス タイプを 1 つのタイプであるかのように操作する方法が必要な場合は、一歩下がって設計を再考する必要があることを強く示しています。

このような設計を続けると、ほとんどの場合Typeable、Thomas M. DuBuisson がコメントで言及しているように をいじったり、存在型 (最近ではよく知られているアンチパターンです) をいじったりすることになります。そのようなアプローチが必要になる場合があるのは事実ですがなぜそれが必要なのかを明確に (たとえ自分自身に対してでも) 説明できない限り、避けるのが最善です。そうしないと、解決するよりもはるかに多くの問題が発生します。

ちなみに、個別の型の利点の一部を保持したい場合は、ファントム型のタグ付けにシングルトン型を使用するか、レコードのコンストラクターを非表示にして、引数PhaseOpsを取るスマート コンストラクターを使用することを検討してください。CurrentPhase

于 2012-09-10T19:04:01.600 に答える