任意类型类约束中的非类型变量参数
Non type-variable argument in the constraint for Arbitrary typeclass
对于 Haskell 从第一性原理编程 第 15 章的练习,我正在尝试基于另一个 Arbitrary
实例:
module AccumulateRight where
import Data.Semigroup
import Test.QuickCheck
data Validation a b = Fail a | Pass b deriving (Eq, Show)
newtype AccumulateRight a b =
AccumulateRight (Validation a b) deriving (Eq, Show)
type TestType = AccumulateRight String [Int]
instance Semigroup b => Semigroup (AccumulateRight a b) where
_ <> (AccumulateRight (Fail x)) = Fail x
(AccumulateRight (Fail x)) <> _ = Fail x
(AccumulateRight (Success a)) <> (AccumulateRight (Success b)) =
AccumulateRight . Success $ a <> b
instance (Arbitrary a, Arbitrary b) => Arbitrary (Validation a b) where
arbitrary = oneof [Fail <$> arbitrary, Pass <$> arbitrary]
instance Arbitrary (Validation a b) => Arbitrary (AccumulateRight a b) where
arbitrary = AccumulateRight <$> arbitrary
semigroupAssoc :: (Eq m, Semigroup m) => m -> m -> m -> Bool
semigroupAssoc a b c = (a <> (b <> c)) == ((a <> b) <> c)
type Assoc = TestType -> TestType -> TestType -> Bool
main :: IO ()
main = quickCheck (semigroupAssoc :: Assoc)
但出现以下错误:
• Non type-variable argument
in the constraint: Arbitrary (Validation a b)
(Use FlexibleContexts to permit this)
• In the context: Arbitrary (Validation a b)
While checking an instance declaration
In the instance declaration for ‘Arbitrary (AccumulateRight a b)’
|
22 | instance Arbitrary (Validation a b) => Arbitrary (AccumulateRight a b) where
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Failed, no modules loaded.
那我是不是做错了什么?为什么我不能在这里使用现有数据的类型类作为约束?
这是一个愚蠢的限制,在人们理解类型类的实现有多么困难之前就已经到位了。事实证明它很容易支持,所以有一个语言扩展——在错误中提到——可以让你这么说。您可以通过添加
来开启它
{-# LANGUAGE FlexibleContexts #-}
到文件的顶部,随着扩展名的增加,这个被认为是完全良性的。但是,在这种情况下,您不应该打开它,而应该只写
instance (Arbitrary a, Arbitrary b) => Arbitrary (AccumulateRight a b)
——毕竟,(Arbitrary a, Arbitrary b)
正是Arbitrary (Validation a b)
成立的条件。
对于 Haskell 从第一性原理编程 第 15 章的练习,我正在尝试基于另一个 Arbitrary
实例:
module AccumulateRight where
import Data.Semigroup
import Test.QuickCheck
data Validation a b = Fail a | Pass b deriving (Eq, Show)
newtype AccumulateRight a b =
AccumulateRight (Validation a b) deriving (Eq, Show)
type TestType = AccumulateRight String [Int]
instance Semigroup b => Semigroup (AccumulateRight a b) where
_ <> (AccumulateRight (Fail x)) = Fail x
(AccumulateRight (Fail x)) <> _ = Fail x
(AccumulateRight (Success a)) <> (AccumulateRight (Success b)) =
AccumulateRight . Success $ a <> b
instance (Arbitrary a, Arbitrary b) => Arbitrary (Validation a b) where
arbitrary = oneof [Fail <$> arbitrary, Pass <$> arbitrary]
instance Arbitrary (Validation a b) => Arbitrary (AccumulateRight a b) where
arbitrary = AccumulateRight <$> arbitrary
semigroupAssoc :: (Eq m, Semigroup m) => m -> m -> m -> Bool
semigroupAssoc a b c = (a <> (b <> c)) == ((a <> b) <> c)
type Assoc = TestType -> TestType -> TestType -> Bool
main :: IO ()
main = quickCheck (semigroupAssoc :: Assoc)
但出现以下错误:
• Non type-variable argument
in the constraint: Arbitrary (Validation a b)
(Use FlexibleContexts to permit this)
• In the context: Arbitrary (Validation a b)
While checking an instance declaration
In the instance declaration for ‘Arbitrary (AccumulateRight a b)’
|
22 | instance Arbitrary (Validation a b) => Arbitrary (AccumulateRight a b) where
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Failed, no modules loaded.
那我是不是做错了什么?为什么我不能在这里使用现有数据的类型类作为约束?
这是一个愚蠢的限制,在人们理解类型类的实现有多么困难之前就已经到位了。事实证明它很容易支持,所以有一个语言扩展——在错误中提到——可以让你这么说。您可以通过添加
来开启它{-# LANGUAGE FlexibleContexts #-}
到文件的顶部,随着扩展名的增加,这个被认为是完全良性的。但是,在这种情况下,您不应该打开它,而应该只写
instance (Arbitrary a, Arbitrary b) => Arbitrary (AccumulateRight a b)
——毕竟,(Arbitrary a, Arbitrary b)
正是Arbitrary (Validation a b)
成立的条件。