摘要Hspec测试

时间:2016-12-07 23:57:31

标签: haskell quickcheck hspec

我正在经历“从第一原理开始的Haskell编程”,我发现自己一遍又一遍地编写代码:

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)

我尝试抽象这个,但在我的水平上,我无法想办法让它发挥作用

我想要完成的是这样的事情

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)

编辑: 在Sapanoia的回答后,我尝试了如下

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 个答案:

答案 0 :(得分: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)。但是,你在这里想要一个forall,因为你希望类型变量fa与顶级变量相同。