2017-12-15 18 views
2

私はhspecとQuickCheckを使用してFunctorのインスタンスのファンクション法を検証しています。私は、私は、このようなコードのブロックを使用して、これらの2をテストしてるの機能式の引数として型コンストラクタを指定します

functorIdentity :: (Functor f, Eq (f a)) => f a -> Bool 

functorComposition :: (Functor f, Eq (f c)) => (Fun a b) -> (Fun b c) -> f a -> Bool 

を持っている:

testListFunctorness :: IO() 
testListFunctorness = 
    hspec $ do 
    describe "list" $ do 
     it "should obey functor identity" $ do 
     property (functorIdentity :: [Int] -> Bool) 
     it "should obey functor composition" $ do 
     property 
      (functorComposition :: (Fun Int String) -> (Fun String Int) -> [Int] -> Bool) 

事はAの同じ特性を試験するために、あります異なるFunctorのインスタンス、[Int]以外のすべてをコピーする必要があります。

testMaybeFunctorness :: IO() 
testMaybeFunctorness = 
    hspec $ do 
    describe "maybe" $ do 
     it "should obey functor identity" $ do 
     property (functorIdentity :: Maybe Int -> Bool) 
     it "should obey functor composition" $ do 
     property 
      (functorComposition :: (Fun Int String) -> (Fun String Int) -> Maybe Int -> Bool) 

異なるFunctorインスタンスに対して多形性のある式を書くことができるはずですが、それをどのように開始するか考えることさえできません。

複数の異なるFunctorにテストロジックのブロックを簡単に再利用するにはどうすればよいですか?あなたは何ができるか

+0

私はここでABの問題があると確信していますが、私はBが何であるか見ることができません:) – N3dst4

答えて

3

は、明示的にtestFunctornessに所望のタイプを渡すことです:

import Data.Proxy 

testFunctorness :: forall a. Functor a => Proxy a -> IO() 
testFunctorness _ = 
    hspec $ do 
    describe "the type" $ do 
     it "should obey functor identity" $ do 
     property (functorIdentity :: a Int -> Bool) 
     it "should obey functor composition" $ do 
     property 
      (functorComposition :: (Fun Int String) -> (Fun String Int) -> a Int -> Bool) 

呼び出しはtestFunctorness (Proxy :: Proxy [])ようになります。

機能内のaがタイプシグニチャのaを参照するように、{-# LANGUAGE ScopedTypeVariables #-}を有効にする必要があります。この場合、は、型検査をする人に、このaが語彙的スコープであることを知らせるために必要です。

+0

ああ、Data.Proxyは素晴らしいです。 QuickCheckを使うために私の制約の中で 'Arbitrary(Int)、Show(Int)、Eq(Int) 'という言葉で終わりましたが、それ以外は完璧です。 – N3dst4

関連する問題