Аргумент без переменной типа в ограничении для Произвольного класса типов - PullRequest
0 голосов
/ 11 сентября 2018

Для упражнения в главе 15 Программирование на Haskell из первых принципов , я пытаюсь написать экземпляр Arbitrary на основе другого 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.

Так я что-то здесь не так делаю? Почему я не могу использовать класс типов существующих данных в качестве ограничения?

1 Ответ

0 голосов
/ 11 сентября 2018

Это глупое ограничение, которое было введено до того, как стало понятно, насколько сложно реализовать классы типов. Оказывается, его достаточно просто поддерживать, поэтому есть языковое расширение, упомянутое в ошибке, которое позволяет вам так говорить. Вы можете включить его, добавив

{-# LANGUAGE FlexibleContexts #-}

в начало вашего файла, и с расширением этот файл считается полностью безопасным. Тем не менее, в этом случае вам не следует включать его, а вместо этого следует просто написать

instance (Arbitrary a, Arbitrary b) => Arbitrary (AccumulateRight a b)

- в конце концов, (Arbitrary a, Arbitrary b) - это как раз те условия, при которых выполняется Arbitrary (Validation a b).

...