抽象 Hspec 测试
Abstracting Hspec tests
我正在经历 "Haskell programming from first principles",我发现自己一遍又一遍地按照以下方式编写代码:
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'。
由于您没有添加错误消息,我认为问题是定义了 (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 在这里,因为您希望类型变量 f
和 a
与顶级变量相同。
我正在经历 "Haskell programming from first principles",我发现自己一遍又一遍地按照以下方式编写代码:
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'。
由于您没有添加错误消息,我认为问题是定义了 (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 在这里,因为您希望类型变量 f
和 a
与顶级变量相同。