2017-12-15 2 views
2

저는 hspec 및 QuickCheck를 사용하여 Functor 인스턴스에 대한 펑터 법칙의 유효성을 검사합니다. 나는이 기능표현식에 대한 인수로 형식 생성자

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이 어휘 적으로 범위가 지정되어야 함을 알리기 위해 forall이 필요합니다.

+0

아, Data.Proxy가 훌륭합니다. QuickCheck를 사용하기 위해서는 제약 조건에서'임의 (Int), 표시 (Int), 이퀄 (Int) '로 끝났지 만 완벽하다는 점을 제외하고는. – N3dst4