Задача состоит в том, чтобы создать класс типов, для которого вы будете определять экземпляр для функций и экземпляр для возвращаемого типа.Тот факт, что это Bool
, вообще не является проблемой.
Мы пытаемся написать функцию, которая принимает аргумент с переменным числом аргументов и возвращает Bool
, поэтому мы определим класс типа стакая функция.
class Stmt a where
tautology :: a -> Bool
Далее мы определим экземпляр для типа возврата переменной функции.В данном случае это Bool
.
-- A Bool is a tautology if it's True.
instance Stmt Bool where
tautology = id
Ключевая часть является следующим экземпляром для функций, которые принимают аргумент Bool
, и тип возвращаемого значения которого является некоторым типом из нашего класса.Таким образом, этот экземпляр будет применяться несколько раз, если функция принимает несколько аргументов.
-- A function is a tautology if it always returns a tautology.
instance Stmt b => Stmt (Bool -> b) where
tautology f = tautology (f True) && tautology (f False)
Для записи этого способа требуется FlexibleInstances
из-за Bool
в заголовке второго экземпляра.Чтобы сделать то же самое с чистым Haskell 98, нам нужно вместо этого использовать переменную типа с соответствующим ограничением.Мы можем, например, использовать Bounded
и Enum
(есть экземпляры для обоих для Bool
), или вы можете создать свой собственный класс, который позволит вам создавать соответствующие входные данные.
instance (Enum a, Bounded a, Stmt b) => Stmt (a -> b) where
tautology f = all (tautology . f) [minBound .. maxBound]
Ибыли сделаны.Давайте попробуем это:
> tautology $ \x y -> (not x && not y) == not (x && y)
False
> tautology $ \x y -> (not x && not y) == not (x || y)
True