2012-09-18 7 views
6

pipesライブラリのタイプクラスを作成して、Proxyのようなタイプの抽象インターフェースを定義しています。型クラスのようなものになります。タイプクラスまたはインスタンスの派生変数を制限する

class ProxyC p where 
    idT :: (Monad m) => b' -> p a' a b' b m r 
    (<-<) :: (Monad m) 
      => (c' -> p b' b c' c m r) 
      -> (b' -> p a' a b' b m r) 
      -> (c' -> p a' a c' c m r) 
    ... -- other methods 

を私はまた形式ですProxyタイプのための拡張機能を書いている:

instance (ProxyC p) => ProxyC (SomeExtension p) where .... 

...と私は、これらのインスタンスができるようにしたいのですがmMonadである場合、p a' a b' b mがすべてa',a,b'およびbの場合にMonadであるという追加の制約を課すことができる。

しかし、ProxyCクラスまたはインスタンスの制約として、それをきれいにエンコードする方法がわかりません。

(<-<) :: (Monad m, Monad (p b' b c' c m), Monad (p a' a b' b m)) 
      => (c' -> p b' b c' c m r) 
      -> (b' -> p a' a b' b m r) 
      -> (c' -> p a' a c' c m r) 

...しかし、私は、よりシンプルでエレガントな解決策があるだろう期待していた:私は現在知っている唯一の解決策は、クラスのメソッドのシグネチャで、それをコードするような何かを行うことです。

編集:そして、それさえも最後の解決策は機能しない、コンパイラは(Monad (SomeExtension p a' a b' b m))には、次のインスタンスを指定した場合でも、変数の特定の選択のための(Monad (p a' a b' b m))を意味することを推測しないため:

instance (Monad (p a b m)) => Monad (SomeExtension p a b m) where ... 

編集#を2

class ProxyC p where 
    return' :: (Monad m) => r -> p a' a b' b m r 
    (!>=) :: (Monad m) => ... 
:私はちょうど ProxyCクラス内 Monadクラスのメソッドを複製している検討している次のソリューション

...それぞれProxyCインスタンスでインスタンス化します。 Monadメソッドは、拡張書き込みのために内部的に使用する必要があるだけで、元のタイプにはダウンストリームユーザー用の適切なMonadインスタンスがまだあるため、これは私の目的にとっては問題ないようです。これは、インスタンス作成者にメソッドMonadを公開するだけです。

+0

AFAIKあなたはf.e.のような醜いハックでしかできません。 Edward Kmettはhttp://hackage.haskell.org/packages/archive/constraints/0.3.2/doc/html/Data-Constraint-Forall.htmlにあります。 –

答えて

1

これを行うにはかなり些細な方法は、あなたが明示的にあなたがそれ

--help avoid type signatures 
monadOf :: IsMonad m -> m a -> IsMonad m 
monadOf = const 

--later on 
case getProxyMonad `monadOf` ... of 
    IsMonad -> ... 

必要な場所の辞書を開く必要があります

data IsMonad m where 
    IsMonad :: Monad m => IsMonad m 

class ProxyC p where 
    getProxyMonad :: Monad m => IsMonad (p a' a b' b m) 

値レベルに証拠を移動するためにGADTを使用していますGADTを使って命題の証明書を渡すという戦法は、実際には非常に一般的です。あなたは、制約の種類だけではなく、GADTsを使用して大丈夫です場合は、代わりにあなたが

getProxyMonad' :: ProxyC p => (Monad m) :- (Monad (p a' a b' b m)) 
getProxyMonad' = Sub getProxyMonad 

を定義した後、コンパイラに伝えるために派手な中置演算子を使用することができますエドワードKmettのData.Constraintパッケージ

class ProxyC p where 
    getProxyMonad :: Monad m => Dict (Monad (p a' a b' b m)) 

を使用することができますどこモナドのインスタンス実際に

... \\ getProxyMonad' 

を探すために、:-含意タイプは、オブジェクトが詐欺あるカテゴリを(形成しますこのカテゴリにはロットという素敵な構造のものがあります。これは、校正を行うのがかなりいいと言います。

p.s.これらのスニペットのいずれもテストされていません。

編集: あなたはまた、私はこの実装にもなることを、疑うが、明らかにテストしていません

newtype WrapP p a' a b' b m r = WrapP {unWrapP :: p a' a b' b m r} 

instance ProxyC p => Monad (WrapP p) where 
    return = case getProxyMonad of 
       Dict -> WrapP . return 
    (>>=) = case getProxyMonad of 
       Dict -> \m f -> WrapP $ (unWrapP m) >>= (unWrapP . f) 

instance ProxyC p => ProxyC (WrapP p) where 
    ... 

すべての場所でGADTsを開く必要のnewtypeラッパーと値のレベルの証明を組み合わせて、ことができませんでした比較的効率的である。

+0

私の懸念は、これに関するオーバーヘッドがどれくらいあるかということです'data'型をラップアンドアンラップします。私はすべての縛りにそのような往復をしていることを忘れないでください。しかし、私はそれをベンチマークしていないので、私のところは純粋な推測です。今、私は 'newtype P pa 'ab' bmr = P(pa 'ab' bmr)'のように見える別の解を持っています。次に、インスタンス(ProxyC p、Monad m)=> Monad(P pa 'ab 'bm)where ... 'とし、すべての' ProxyC'メソッドを署名に 'P'を入れるように変更します。 –

+0

ディクショナリの正規化トリックは機能しましたが、エドワードの 'constraint'パッケージを使用して終了しました。 –

関連する問題