2017-11-14 14 views
2

、私はここでHaskellの任意の型クラスのインスタンス戻り値の型

quickCheck (semigroupAssoc :: IdentAssoc) 

で呼び出す、

semigroupAssoc :: (Eq m, S.Semigroup m) => m -> m -> m -> Bool 
semigroupAssoc a b c = 
    (a S.<> (b S.<> c)) == ((a S.<> b) S.<> c) 

type IdentAssoc = Identity String -> Identity String -> Identity String -> Bool 

のための任意の型クラスのインスタンス

instance (Arbitrary a) => Arbitrary (Identity a) where 
    arbitrary = do 
     a <- Test.QuickCheck.arbitrary 
     return (Identity a) 
をquickcheckテストをされて書いています

私の任意のインスタンスでは、(アイデンティティa)またはちょうどaを返すことができます。 (Identity a)は正しいですが、コンパイルエラーがなく、実行すると無限ループが発生します。どうしてこれなの?

+0

同じ機能をもう一度呼び出すだけです。 –

+0

私は再びどの機能を呼びますか? – tesserakt

+0

あなたが定義したものです。 –

答えて

4

タイプの推論は、arbitraryの呼び出しをと同じのインスタンスに変更し、無限ループを引き起こします。

instance (Arbitrary a) => Arbitrary (Identity a) where 
    arbitrary = do 
     x <- Test.QuickCheck.arbitrary -- this calls arbitrary @ a 
     return (Identity x) 

instance (Arbitrary a) => Arbitrary (Identity a) where 
    arbitrary = do 
     x <- Test.QuickCheck.arbitrary -- this calls arbitrary @ (Identity a) 
     return x 

クラスメソッドを呼び出すたびに、コンパイラは呼び出すインスタンスを推論します。

前者の場合、コンパイラはx :: aを推論します(このタイプのみがコードタイプチェックを行います)。したがって、arbitrary @ aを呼び出します。

後者の場合、コンパイラはx :: Identity aを推論します(このタイプのみがコードタイプチェックを行います)。したがって、arbitrary @ (Identity a)を呼び出し、無限ループを引き起こします。

+0

優秀、私の目の前にあった。助けてくれてありがとう。 – tesserakt

+0

これは戻り値の型を変更しませんか?なぜコンパイラはそれをキャッチしませんでしたか? – tesserakt

+0

@tesserakt私は最後の編集がこれを少し明確にすることを願っています。 – chi

4

あなたのようにそれを記述する場合:

instance Arbitrary a => Arbitrary (Identity a) where 
    arbitrary = do 
     x <- arbitrary 
     return x

(私はそれほど混乱を引き起こすことがxaに改称)。

次に、ハスケルはタイプ配管を行います。return xと書いているので、xはタイプIdentity aでなければなりません。そして、私たちはちょうど定義したarbitrary :: Arbitrary a => Gen aが存在するので、私たちは幸運です(ここで太字で記入してください)。

これは、無限ループを構築したことを意味します。たとえば、Javaの場合、次のようになります。

もちろん、このような関数を定義することはできますが、型をチェックすると正しいと思います。 Haskellはこれを導出します

instance Arbitrary a => Arbitrary (Identity a) where 
    arbitrary = do 
     x <- arbitrary 
     return Identity x

:私たちはあなたがしかし書いた場合、再び...、再び

をその関数を呼び出して、もう一度、とするのと同じ関数を呼び出しておくので、しかし、誰の進歩は、もちろんありませんxのタイプはaです。 Arbitrary aは、ある意味ではarbitrary :: Arbitrary a => Gen aという機能がありますが、それは別のものです(ここでは太字で書いていません)。そして、その値を生成することになります私たちはIdentityコンストラクタでラップします。確かに:最初の例では、私たちもArbitrary a制約を追加する必要がないこと

注我々は、任意のaを生成することはありませんので、

instance Arbitrary (Identity a) where 
    arbitrary = do 
     x <- arbitrary 
     return x

これは、うまくコンパイルします。

関連する問題