2016-12-07 4 views
1

をテストSapan後 :それは私が達成したかった何抽象化Hspecは、私は、「第一原理からのHaskellプログラミング」を経由していると私は自分自身が何度も次の方法でコードを書いた

を動作させるための方法を把握するために、この

checkFunctor :: (Functor f) => String -> f a -> IO() 
checkFunctor description f = hspec $ do 
     describe description $ do 
      it "identity property" $ do 
       property $ (functorIdentity :: f a -> TypeIdentity) 
      it "composition property" $ do 
       property $ (functorComposition :: f a -> TypeComposition) 

EDITのようなものでした

type TypeIdentity = Bool 
type TypeComposition = Fun Int Int -> Fun Int Int -> Bool 


checkFunctor :: forall f a. (Functor f) => String -> f a -> IO() 
checkFunctor description f = hspec $ do 
    describe description $ do 
     it "identity property" $ do 
      property $ (functorIdentity :: f a -> TypeIdentity) 
     it "composition property" $ do 
      property $ (functorCompose' :: f a -> TypeComposition) 

を次のようにイアの答えは、私が試したが、私は次のエラーを取得する

FunctorCheck.hs:22:25: error: 
• Couldn't match type ‘a’ with ‘Int’ 
    ‘a’ is a rigid type variable bound by 
    the type signature for: 
     checkFunctor :: forall (f :: * -> *) a. 
         Functor f => 
         String -> f a -> IO() 
    at FunctorCheck.hs:16:26 
    Expected type: f a -> TypeComposition 
    Actual type: f Int -> Fun Int Int -> Fun Int Int -> Bool 

私は任意の値と関数を生成するために型を定義することは、その後かなり複雑になります。

checkFunctorのタイプを次のような特定のタイプにバインドする方法はありますか?当然の

checkFuntor :: checkFunctor :: forall f Int. (Functor f) => String -> f a -> IO() 

私はこれを試してみましたが、それは私のパースエラーを与え、私はそれがちょうど私が正しく「FORALL」を使用していないと仮定します。

+1

はい、可能です。 'ScopedTypeVariables'を使ってこれを行うことができます.GHC 8の' TypeApplications'と 'AllowAmbiguousTypes'を使ってより良いものにすることができます。 –

+0

'forall'は新しい型*変数*を導入するために使われます。 * 'Int'のような具象型は導入する必要はなく、型変数*の代わりに挿入するだけです。あなたの例は次のようになります: 'checkFunctor :: forall f。 (Functor f)=>文字列 - > f Int - > IO() ' 'checkFunctor'の本体には、それに応じて' functorIdentity :: f Int - > TypeIdentity'が必要です。 – sapanoia

答えて

1

エラーメッセージを追加していないので、問題はタイプエラーであると仮定します。ここでは、(functorIdentity :: f a -> TypeIdentity)が定義されています。問題は、ここで紹介したfが新しく、最上位署名のfとは異なることです。これを解決するには、以下の拡張子を有効にします。

{-# LANGUAGE ScopedTypeVariables #-} 

をそしてcheckFunctorへの署名を変更します。

checkFunctor :: forall f a. (Functor f) => String -> f a -> IO() 

forallが新しい型変数を紹介します。 ScopedTypeVariablesがなく、明示的にforallが指定されている場合は、常に暗黙的に存在し、(functorIdentity :: f a -> TypeIdentity)(functorIdentity :: forall f a. f a -> TypeIdentity)になります。しかし、を入力しないでください。faの型変数をトップレベルのものと同じにしたいので、ここではは不要です。

+0

あなたの答えをありがとう!私はこれを試した後に質問を編集しましたが、成功しませんでした –

関連する問題