4

次のGADTがあるとします:

data Stage a b where
    Comb :: Stage a b -> Stage b c -> Stage a c
    FMap :: (a -> b) -> Stage a b

私は今、次のように機能する関数が欲しいです:

run (a `Comb` b) = (a,b)
run (FMap f)     = (FMap f,FMap id)

そのような関数をどのように構築しますか?

タイプをバインドするさまざまな方法を試しましたが、成功しませんでした。より広範な型バインディングを可能にする、不足している拡張機能はありますか?

これはエラーメッセージです:

Couldn't match type `t' with `(Stage t1 b, Stage b t2)'
  `t' is a rigid type variable bound by
      the inferred type of run :: Stage t1 t2 -> t at <interactive>:11:5
In the expression: (a, b)
In an equation for `run': run (a Comb b) = (a, b)

達成したいことの説明: DSL と、いくつかの異なる方法で DSL のコードを実行しようとする関数 run を設計したいと考えています (それぞれの方法に複数の異なる run 関数があります)。run 関数は、与えられたコードをできるだけ多く実行しようとし、実行できなかったコードと、実行できたコードの結果を報告します。

4

1 に答える 1

7

runGADT でパターン マッチングを行っているため、の型シグネチャが必要になります。GADT でのパターン マッチングには型の改良が必要であり、これは通常、型シグネチャがある場合にのみ機能します。

しかし、型シグネチャがどうなるかは不明です。入力値が

a `Comb` b :: Stage x y

その後(a, b)、どこに戻りますか

a :: Stage x b
b :: Stage b y

不明な点がありbます。これは存在型のエスケープです。あなたは書くことができません

run :: Stage x y -> (State x b, Stage b y)

これは、すべてに対して機能する必要があることを意味しますが 、一部の(不明な)に対してbのみ機能するためです。b

残念ながら、なぜ のような関数を書きたいのかは明確ではありませんrun。なぜペアを作るのですか?このペアを後でどうしたいですか?コンストラクターは、Comb不明な中間型を持つ 2 つのステージを結合するように定義されているため、このバージョンのrunは機能します。

run :: Stage a b -> Stage a b
run (a `Comb` b) = a `Comb` b
run (FMap f)     = FMap f `Comb` FMap id

または、中間型が不明な 2 つのステージの「ペア」のみを許可する、より具体的なデータ型を定義することもできます。

data PairStages a b where
  PairStages :: Stage a b -> Stage b c -> PairStages a c

その後:

run :: Stage a b -> PairStages a b
run (a `Comb` b) = PairStages a b
run (FMap f)     = PairStages (FMap f) (FMap id)

runしかし、ペアを返すのはまだ奇妙に感じます。私が言ったように、 の結果で何をしたいのかは不明ですrun。ケースrun内のコンポーネントを実行した結果を実際に何らかの方法で組み合わせる再帰関数があると、より便利に思えます。Combたとえば、次のようにします。

run :: Stage a b -> (a -> b)
run (a `Comb` b) = run b . run a
run (FMap f)     = f
于 2013-03-06T19:44:59.593 に答える