Я хочу создать два класса типов, A
и B
, где A
- суперкласс B
.Функции, определенные в B
, достаточны для реализации функций в A
.Затем, если у меня есть функция с ограничением fun :: (A thing) => ...
экземпляр B
для, скажем, Int
, я хотел бы иметь возможность передать Int
в fun
без создания дублирующего экземпляра A
для Int
.
Например, допустим, у меня есть класс типов, который может проверить, является ли значение "четным".Затем у меня есть другой класс типов, который может проверить, делится ли значение на некоторое число.Класс второго типа является достаточно мощным для реализации функций первого, и любая функция, которая требует только возможности «четной проверки», должна иметь возможность принимать аргумент, обладающий способностями «делимого на».
Воткак мне кажется, это будет выглядеть так:
class IsEven a where
isEven :: a -> Bool
class (IsEven a) => DivisibleBy a where
divisibleBy :: a -> Int -> Bool
isEven :: a -> Bool
isEven a = divisibleBy a 2
printIsEven :: (IsEven a) => a -> IO ()
printIsEven a = putStrLn (show (IsEven.isEven a))
instance IsEven Int -- I need to do this or I cannot create a DivisibleBy instance
instance DivisibleBy Int where
divisibleBy a i = a `mod` i == 0
myint :: Int
myint = 2
main :: IO ()
main = printIsEven myint
Однако во время компиляции выдается предупреждение:
[2 of 2] Compiling Main ( Foo.hs, Foo.o )
Foo.hs:11:10: warning: [-Wmissing-methods]
• No explicit implementation for
‘IsEven.isEven’
• In the instance declaration for ‘IsEven Int’
|
11 | instance IsEven Int
| ^^^^^^^^^^
Linking Foo ...
и во время выполнения программа завершается ошибкой:
Foo: Foo.hs:11:10-19: No instance nor default method for class operation isEven
Как мне добиться этого эффекта подтипа, не дублируя логику в instance IsEven
?