在Semigroup的《第一原理》一书中的Haskell编程练习中,要求我为用户定义的类型类写group_by(.id)[]|add
。类型类很多,但我什至不了解如何编写基本类:
第一个用于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
使参数化类型的参数具体化。但这也不起作用。
第三,我不知道该怎么写。但我认为它类似于第二个。
有人可以对此进行解释,以便我理解如何编写参数化Semigroup的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
吗?
答案 0 :(得分:3)
这是错误的:
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
是我们可以为其生成随机样本的类型(在Arbitrary a =>
之后添加Instance
)。否则,我们无法使用x <- arbitrary
为a
生成样本。
进一步:
type IdentityAssoc =
(Identity a0) -> (Identity a1) -> (Identity a2) -> Bool
在这里我们不能引用a1,a1,a2
,因为我们没有在任何地方定义这些类型。我们需要选择具体的类型,例如Int
。此外,这三种类型必须是同一类型,因为(<>)
接受两个相同类型的值,并返回该类型的值。