如何在参数化类型上编写“ Semigroup”实例及其“ quickCheck”对象?

时间:2018-10-22 11:08:34

标签: haskell semigroup

在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吗?

1 个答案:

答案 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 <- arbitrarya生成样本。

进一步:

type IdentityAssoc =
  (Identity a0) -> (Identity a1) -> (Identity a2) -> Bool

在这里我们不能引用a1,a1,a2,因为我们没有在任何地方定义这些类型。我们需要选择具体的类型,例如Int。此外,这三种类型必须是同一类型,因为(<>)接受两个相同类型的值,并返回该类型的值。