2016-12-07 13 views
1

을 테스트하고 나 자신에 비해 다음과 같은 방식으로 코드를 작성하고 이상 발견추출 Hspec 내가 "첫 번째 원칙에서 하스켈 프로그램"을 통해 갈거야

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

checkSomething :: IO() 
checkSomething = hspec $ do 
     describe "Some functor" $ do 
      it "identity property" $ do 
       property $ (functorIdentity :: TypeIdentity) 
      it "composition property" $ do 
       property $ (functorComposition :: TypeComposition) 
내가 이것을 추출 시도

하지만 내 수준에서 내가 할 수 없습니다입니다 Sapan 후 : 그것은 내가이

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) 

편집과 같은 무언가를 달성하기 위해 좋아했을 것

를 작동하게하는 방법을 알아낼

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) 

을 다음과 같이 이아 (Oia)의 대답은 내가 시도했지만 나는 다음과 같은 오류가 발생합니다

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이 최상위 유형 변수와 동일하기를 원하기 때문에 여기서 forall을 원합니다.

+0

답변 해 주셔서 감사합니다! 나는 이것을 시도한 후에 질문을 편집했으나 성공하지 못했습니다. –