Избегайте повторяющихся экземпляров и дублирования кода [дубликаты]

Скажем, у меня есть класс типов Convertable:

{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances #-}

class Convertable a b where
    convert :: a -> b

Прежде всего, преобразование одного типа в тот же тип — это тождество:

instance Convertable a a where
    convert = id

Допустим, мы хотим преобразовать целые числа в числа с плавающей запятой:

instance Convertable Int Float where
    convert = fromIntegral

instance Convertable Float Int where
    convert = round

Все идет нормально. Но я хотел бы обобщить это, чтобы включить все интегральные типы и все RealFracs:

instance (Integral a, RealFrac b) => Convertable a b where
    convert = fromIntegral

instance (RealFrac a, Integral b) => Convertable a b where
    convert = round

GHC не нравится это:

  Duplicate instance declarations:
    instance (Integral a, RealFrac b) => Convertable a b
      -- Defined at test.hs:9:10
    instance (RealFrac a, Integral b) => Convertable a b
      -- Defined at test.hs:12:10

Есть ли хорошее решение для этого, которое избавляет меня от создания m x n экземпляров?


person Emil Eriksson    schedule 17.02.2014    source источник
comment
Проблема в том, что компилятор не знает, что что-то не может быть экземпляром одновременно Integral и RealFrac.   -  person David Young    schedule 18.02.2014
comment
Я думал, что поведение будет таким же, как и с перекрывающимися экземплярами: пока это не используется перекрывающимся образом, все в порядке. Но, видимо, это не так.   -  person Emil Eriksson    schedule 18.02.2014
comment
Даже если бы это было возможно, не было бы хорошей идеей использовать его таким образом. Операции с потерями, такие как round, всегда должны быть явными, IMO, что хорошо продемонстрировали 50 лет программирования на C. И более явно, чем просто конвертировать, потому что это не то. Тем не менее... конечно, есть приложения, в которых можно сказать, что такая универсальная функция преобразования полезна, и действительно существует установленная библиотека, которая прошла через все трудности определения экземпляра за экземпляром. Он также имеет Float -> Int...   -  person leftaroundabout    schedule 18.02.2014