2015-12-04 15 views
6

このタイトルは、あまり説明的ではありませんが、短いタイトルでこれをどのように記述するかわかりません。私はどんな勧告にも感謝しています!一般的なtypeclassインスタンスを一連の小さなインスタンスから推論しますか?

私は私の問題の非常に単純化されたバージョンを提示するつもりです:)

だから私は与えられたの正規の建設を生成することができるようになっている型クラス

class Known f a where 
    known :: f a 

を持っています特定のインデックスに入力すると、GADTなどで作業するのに便利です。私はthisの簡略化されたバージョンを提供しています。

instance Known Proxy a where 
    known = Proxy 

我々が使用することができます:

だから、明らかにProxyのインスタンスがあります

> known :: Proxy Monad 
Proxy 

をしかしthis HList-like typeのインスタンスもあります:

data Prod f :: [k] -> * where 
    PNil :: Prod f '[] 
    (:<) :: f a -> Prod f as -> Prod f (a ': as) 

infixr 5 (:<) 

はどこProd f '[a,b,c]はなりおおよそに相当するタプル。同じFunctor、異なるタイプ。インスタンスを書く

はちゃんと簡単です:

> known :: Prod Proxy '[1,2,3] 
Proxy :< Proxy :< Proxy :< PNil 

しかし、私は私が作る必要がある場合にはよ(表示するインスタンスを想定):かなりうまく動作します

instance Known (Prod f) '[] where 
    known = PNil 
instance (Known f a, Known (Prod f) as) => Known (Prod f) (a ': as) where 
    known = known :< known 

すべてasに "多型"関数がありますが、GHCはそれを好きではありません。

asProds :: forall as. Proxy as -> Prod Proxy as 
asProds _ = known :: Prod Proxy as 

それは、このエラーを思い付く:

私は、GHCはそれはそれは 任意の asのために動作します選択されますインスタンスが存在することを示すことができないと言っていると思います
No instance for (Known (Prod f) as) 
    arising from a use of 'known' 

または、そのインスタンスに対してknownを構築する戦略がありません。

私は人間として、これが当てはまることを知っていますが、これを動作させる方法はありますか?インスタンスはすべて「範囲内」で利用可能ですが、どのようにGHCに満足する方法でそれを構築するかを教えてもらえますか?

答えて

5

クラスに制約がない場合は、そのメソッドを使用できません。

種類が消去されているので
asProds (_ :: Proxy as) = known :: Prod Proxy as 
-- inferred constraint 

、があります何のインスタンスは、そもそも辞書が存在しない場合にランタイムを構築することができ、そこから:GHCはこの型を推測できることを

asProds :: forall as. Known (Prod Proxy) as => Proxy as -> Prod Proxy as 
asProds _ = known :: Prod Proxy as 

注:ちょうど制約を追加。あらゆる種類の住人が存在することは論理的には真実かもしれませんが、プログラムのためには、建設的な証明 - を実行する必要があります。

すべてのケースのインスタンスがある場合、インスタンスが必要なときには、頻繁に例外を除いてインスタンスを取得できるため、制約を書き留めても大変です。例外は、タイプファミリアプリケーションの開いたタイプのインスタンスが必要な場合です。その場合は、他の既知のインスタンスから必要な型のインスタンスを明示的に作成する関数を記述する必要があります。

+0

Ah。残念なことに、このような制約を回避することが、私が最初にこれを実行する理由です。しかし!私の問題は、当初、私の存在のすべてに対して '(Applicative(Foo ns)、Foldable(Foo ns)) 'などを指定する必要があり、これですべてを取り除くことができると思ったのです。しかし、今私は、これらのさまざまな制約のすべてを「Known」制約に置き換えることができることを確認しました。制約を回避することはできませんが、今では1つのキャッチオールを持つだけで、はるかにクリーンです。ありがとう! –

+0

@ JustinL。 [constraint synonyms](https://downloads.haskell.org/~ghc/7.8.4/docs/html/users_guide/constraint-kind.html)を使用することもできます: '既知のns =(Applicative(Foo ns) 、Foldable(Foo ns)、...) 'を実行します。 –

+0

@AlexeyRomanovそれはまだ私に非常にアドホックでun-haskellを感じる。私は、種類の実際のデータコンストラクタに属していない非常にまれな/まれであいまいな使い方しか持たないインスタンスをたくさん投げてしまうかもしれません...それはあまりにも曖昧なクラスとは関係がありませんすべて。そして、私は新しいインスタンスを書くたびに、クラスを追加して作業を複製する必要があります。 –

関連する問題