У меня есть тип алгебраических данных с некоторыми конструкторами, которые имеют сопоставимые значения, и некоторые конструкторы, которые этого не делают. Я написал несколько функций сравнения, которые работают как стандартные операторы (==)
и (/=)
, но возвращают Nothing
для сравнения, которые не имеют смысла:
data Variant = IntValue Int
| FloatValue Float
| NoValue
equal :: Variant -> Variant -> Maybe Bool
equal (IntValue a) (IntValue b) = Just (a == b)
equal (FloatValue a) (FloatValue b) = Just (a == b)
equal _ _ = Nothing
unequal :: Variant -> Variant -> Maybe Bool
unequal (IntValue a) (IntValue b) = Just (a /= b)
unequal (FloatValue a) (FloatValue b) = Just (a /= b)
unequal _ _ = Nothing
Это работает, но повторение неудобно - тем более, что на самом деле у меня больше конструкторов Variant
и больше функций сравнения.
Я думал, что могу отбросить повторение в вспомогательную функцию, параметризованную на функции сравнения:
helper :: (Eq a) => (a -> a -> Bool) -> Variant -> Variant -> Maybe Bool
helper f (IntValue a) (IntValue b) = Just (f a b)
helper f (FloatValue a) (FloatValue b) = Just (f a b)
helper _ _ _ = Nothing
equal' :: Variant -> Variant -> Maybe Bool
equal' = helper (==)
unequal' :: Variant -> Variant -> Maybe Bool
unequal' = helper (/=)
но это не работает, потому что переменная типа a
, по-видимому, не может одновременно связываться с Int
и Float
в определении helper
; GHC привязывает его к Float
, а затем жалуется на несоответствие типа в строке, которая обрабатывает IntValue
.
Функция, подобная (==)
, является полиморфной при непосредственном использовании; есть способ передать его другой функции и оставить ее полиморфной?