У меня есть алгебраический тип данных с некоторыми конструкторами, которые содержат сопоставимые значения, и некоторыми конструкторами, которые не имеют. Я написал несколько функций сравнения, которые работают как стандартные операторы (==)
и (/=)
, но возвращают 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
.
Функция, подобная (==)
, полиморфна при непосредственном использовании; Есть ли способ передать его в другую функцию и оставить его полиморфным?