Как написать экземпляр `Semigroup` и их` quickCheck` для параметризованных типов? - PullRequest
0 голосов
/ 22 октября 2018

В упражнениях по программированию на Haskell из книги Первых принципов по полугруппе меня просят написать 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 произвольно?

1 Ответ

0 голосов
/ 22 октября 2018

Это неправильно:

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.Кроме того, эти три типа должны быть одного типа, поскольку (<>) принимает два значения одного типа и возвращает значение этого типа.

...