2017-04-07 12 views
0

パラメータ型クラスを使いたいです。以下は、私のソースコードは次のとおりです。ハスケル型クラスのあいまいな型

コンパイル時に
class (CContext3D c k v) => CBuilder3D c a k v where 
    build3D :: c -> a -> String -> HSL HLangJS HLangJS 

私は次のエラーが表示されます

Could not deduce (CBuilder3D c a k0 v0) 
from the context: CBuilder3D c a k v 
bound by the type signature for: 
    build3D :: CBuilder3D c a k v => 
           c -> a -> String -> HSL HLangJS HLangJS 

次のコードは正常に動作します。

それはクラスのインスタンスを解放する可能性がある方法
class (CContext3D c KeyContext3D String) => CBuilder3D c a where 
    build3D :: c -> a -> String -> HSL HLangJS HLangJS 

kとvの型によって異なりますか?

答えて

2

build3Dへの呼び出しがあるとします。その呼び出しのコンテキストから、コンパイラは適切なインスタンスを見つけなければなりません。これには変数c a k vの値を検索する必要があります。ただし、build3Dのタイプにはk vが含まれていないので、それらを見つけることは不可能です。

より具体的には、私たちが持っていた場合

instance CBuilder3D c a K1 V1 where ... 
instance CBuilder3D c a K2 V2 where ... 

その関連build3D機能はまったく同じタイプを持っているでしょうし、コンパイラは、それらのいずれかを選択する方法がありません。

考えられる解決策:

可能な場合は、kvの値は他のパラメータによって決定されていることを述べるために関数従属性やタイプファミリを使用する必要があります。これはあなたの特定のクラスに応じて、そうでないかもしれません。

そうでない場合は、AllowAmbiguousTypesTypeApplicationsを有効にして、あいまいなタイプを回避してください。ただし、すべての呼び出しで、これらの型を明示的にbuild3D @t1 @t2 @t3 @t4 x1 x2 x3のように指定する必要があります。ここで、t1,...はすべての変数c a k vの型です。それほど便利ではない。

別のオプションは、k,vはプロキシとタイプに表示されるようにすることです:

import Data.Proxy 

class (CContext3D c k v) => CBuilder3D c a k v where 
    build3D :: proxy k -> proxy v -> c -> a -> String -> HSL HLangJS HLangJS 

今、各呼び出しはbuild3D (Proxy :: Proxy K1) (Proxy :: Proxy V1) x1 x2 x3のようなものでなければなりません。