2013-01-04 29 views
5

私は、実行を「見る」ためにモノイドを含む応用ファンクタに取り組んでいます。しかし、時には私はこの部分をまったく気にしないので、モノオイドの選択は決して消費されないので無関係です。制限付きの制約タイプとタイプファミリーを '限定された'制約付きで使用する

{-# LANGUAGE FlexibleInstances #-} 
{-# LANGUAGE ConstraintKinds #-} 
{-# LANGUAGE MultiParamTypeClasses #-} 
{-# LANGUAGE TypeFamilies #-} 

import GHC.Exts 

class Render a b where render :: a -> b 
instance Render a() where render = const() 

class Merge a where 
    type Renderer a b :: Constraint 
    merge :: Renderer a b => a -> b 

data Foo = Foo Bool 

instance Merge Foo where 
    type (Renderer Foo) m = (Render Bool m) 
    merge (Foo b) = render b 

Renderは単一bに様々なa Sを変換するために使用されています。私は私が持っているものに簡略化されてきました。 Mergeは私の実際のファンクタを大幅に簡略化していますが、それは型のファミリ/制約が含まれており、その意図は正確にRenderMergeが必要とするものを指定することです。

さて、私のようなものに似ている、「実行」Mergeしたいのですが、ビューを捨てるかもしれません:

runFoo :: Merge a => a -> Int 
runFoo x = case merge x of() -> 5 

しかしので、これは失敗します。

は推測できませんでした私はFなぜなら私のモノイドとして()を選んだmerge

の使用に起因する(Renderer a()) orall aの場合、Render a()というインスタンスがあります。だから、もしMerge aがコレクションRenderのコレクションを意味すると言うならば、これはうまくいくでしょう。もちろん、Merge aより一般的です。コンパイルエラーを説明する任意の制約を追加する可能性があります。

なしでの署名を変更するととにかくありますか?runFooの署名を変更しますか?

+0

は 'Renderer'は常に1つ' Render'が含まれていますか? –

+0

@Tinctorius - いいえ、一般的に 'Foo'のフィールドにある別個の型の量に依存します – ocharles

+0

' Merge'に 'b'もパラメータとして持たない理由はありますか? –

答えて

6

あなたはこれらのケースの多くを持っている場合、これはスケールしないことがありますが、これは動作します:

class Renderer a() => Merge a where 
    ... 
+0

私はそれを考慮していませんでした。私は '' Merge''が最低でも '' monoid ''でレンダリングをサポートしなければならないので、この制約を読むことができました。しかし、これは 'UndecidableInstances'を引き起こします。 – ocharles

+0

"UndecidableInstancesは危険なフラグではありません。型チェッカーが「間違っている」プログラムを受け入れることは決してありません。フラグを使用することの唯一の悪い結果は、型チェッカーがコンテキストスタック深度の制限を考慮して、プログラムのタイプが正しいかどうかを判断できない可能性があるということです。 http://okmij.org/ftp/Haskell/TypeClass.html#undecidable-inst-defense –

+0

私はすでに3つの場所でそれを使用していることを知っています;しかし、理想的には、それを必要としないソリューションを見つけるのが好きです。純粋に学術的な理由であっても。私はおそらくこの答えを受け入れるだろう、ちょっと地面を少しだけ開いたままにしておく。これは実際に治療を働いています! – ocharles