如何在参数化类型上编写“Semigroup”实例及其“quickCheck”?
How to write `Semigroup` instance and their `quickCheck`s on parameterized types?
在关于 Semigroup 的 Haskell Programming from First Principle 这本书的练习中,我被要求为用户定义的类型类编写 quickCheck
。类型类很多,但我连最基本的都不知道怎么写:
问题:
第一个是 Trivial
:
module Exercise where
import Test.QuickCheck
data Trivial =
Trivial
deriving (Eq, Show)
instance Semigroup Trivial where
_ <> _ = undefined
instance Arbitrary Trivial where
arbitrary = return Trivial
semigroupAssoc :: (Eq m, Semigroup m) => m -> m -> m -> Bool
semigroupAssoc a b c = (a <> (b <> c)) == ((a <> b) <> c)
type TrivialAssoc = Trivial -> Trivial -> Trivial -> Bool
第二个是
newtype Identity a = Identity a
第三个用于:
data Two a b =
Two a b
我的答案:
首先,我将 instance
表达式更改为
instance Semigroup Trivial where
_ <> _ = Trivial
而且有效。
我尝试了以下代码,但第二个代码不起作用:
newtype Identity a = Identity a
instance (Semigroup a) => Semigroup (Identity a) where
(Identity a1) <> (Identity a2) = Identity (a1 <> a2)
instance Arbitrary (Identity a) where
arbitrary = return (Identity a)
type IdentityAssoc =
(Identity a0) -> (Identity a1) -> (Identity a2) -> Bool
main :: IO ()
main =
quickCheck (semigroupAssoc :: IdentityAssoc)
我发现我不明白 quickTest
应该检查什么。我什至试过:
import Data.NonEmpty
newtype Identity a = Identity a
instance (Semigroup a) => Semigroup (Identity a) where
(Identity a1) <> (Identity a2) = Identity (a1 <> a2)
instance Arbitrary (Identity a) where
arbitrary = return (Identity a)
type IdentityAssoc =
(Identity (NonEmpty Int)) -> (Identity (NonEmpty Int)) -> (Identity (NonEmpty Int)) -> Bool
main :: IO ()
main =
quickCheck (semigroupAssoc :: IdentityAssoc)
使参数化类型的参数具体化。但是也没用。
第三个,不知道怎么写。不过我觉得和第二个差不多
有人可以解释一下这些,以便我可以理解如何编写参数化半群的 instance
及其 quickTest
任意值吗?
这是错误的:
instance Arbitrary (Identity a) where
arbitrary = return (Identity a)
a
不是值变量,是类型变量。我们需要 a
类型的值传递给 Identity
构造函数,而不是 a
类型本身。
所以我们需要像
这样的东西
instance Arbitrary a => Arbitrary (Identity a) where
arbitrary = do
x <- arbitrary -- generate a value of type a
return (Identity x) -- turn it into a value of type (Identity a)
(或者,更简洁地说,arbitrary = Identity <$> arbitrary
)
请注意我们如何要求 a
是我们可以为其生成随机样本的类型(在 Instance
之后添加 Arbitrary a =>
)。否则,我们无法使用 x <- arbitrary
为 a
.
生成样本
进一步:
type IdentityAssoc =
(Identity a0) -> (Identity a1) -> (Identity a2) -> Bool
这里我们不能引用 a1,a1,a2
,因为我们没有在任何地方定义这些类型。我们需要选择具体的类型,比如 Int
。此外,这三种类型必须是同一类型,因为 (<>)
取两个相同类型的值,而 returns 取该类型的一个值。
在关于 Semigroup 的 Haskell Programming from First Principle 这本书的练习中,我被要求为用户定义的类型类编写 quickCheck
。类型类很多,但我连最基本的都不知道怎么写:
问题:
第一个是 Trivial
:
module Exercise where
import Test.QuickCheck
data Trivial =
Trivial
deriving (Eq, Show)
instance Semigroup Trivial where
_ <> _ = undefined
instance Arbitrary Trivial where
arbitrary = return Trivial
semigroupAssoc :: (Eq m, Semigroup m) => m -> m -> m -> Bool
semigroupAssoc a b c = (a <> (b <> c)) == ((a <> b) <> c)
type TrivialAssoc = Trivial -> Trivial -> Trivial -> Bool
第二个是
newtype Identity a = Identity a
第三个用于:
data Two a b =
Two a b
我的答案:
首先,我将 instance
表达式更改为
instance Semigroup Trivial where
_ <> _ = Trivial
而且有效。
我尝试了以下代码,但第二个代码不起作用:
newtype Identity a = Identity a
instance (Semigroup a) => Semigroup (Identity a) where
(Identity a1) <> (Identity a2) = Identity (a1 <> a2)
instance Arbitrary (Identity a) where
arbitrary = return (Identity a)
type IdentityAssoc =
(Identity a0) -> (Identity a1) -> (Identity a2) -> Bool
main :: IO ()
main =
quickCheck (semigroupAssoc :: IdentityAssoc)
我发现我不明白 quickTest
应该检查什么。我什至试过:
import Data.NonEmpty
newtype Identity a = Identity a
instance (Semigroup a) => Semigroup (Identity a) where
(Identity a1) <> (Identity a2) = Identity (a1 <> a2)
instance Arbitrary (Identity a) where
arbitrary = return (Identity a)
type IdentityAssoc =
(Identity (NonEmpty Int)) -> (Identity (NonEmpty Int)) -> (Identity (NonEmpty Int)) -> Bool
main :: IO ()
main =
quickCheck (semigroupAssoc :: IdentityAssoc)
使参数化类型的参数具体化。但是也没用。
第三个,不知道怎么写。不过我觉得和第二个差不多
有人可以解释一下这些,以便我可以理解如何编写参数化半群的 instance
及其 quickTest
任意值吗?
这是错误的:
instance Arbitrary (Identity a) where
arbitrary = return (Identity a)
a
不是值变量,是类型变量。我们需要 a
类型的值传递给 Identity
构造函数,而不是 a
类型本身。
所以我们需要像
这样的东西instance Arbitrary a => Arbitrary (Identity a) where
arbitrary = do
x <- arbitrary -- generate a value of type a
return (Identity x) -- turn it into a value of type (Identity a)
(或者,更简洁地说,arbitrary = Identity <$> arbitrary
)
请注意我们如何要求 a
是我们可以为其生成随机样本的类型(在 Instance
之后添加 Arbitrary a =>
)。否则,我们无法使用 x <- arbitrary
为 a
.
进一步:
type IdentityAssoc =
(Identity a0) -> (Identity a1) -> (Identity a2) -> Bool
这里我们不能引用 a1,a1,a2
,因为我们没有在任何地方定义这些类型。我们需要选择具体的类型,比如 Int
。此外,这三种类型必须是同一类型,因为 (<>)
取两个相同类型的值,而 returns 取该类型的一个值。