Развлекайтесь с типами! Разрешение нескольких объявлений экземпляров

Я пытаюсь написать код на Haskell, в котором есть несколько типов данных, каждый из которых может иметь несколько реализаций. Для этого я определяю каждый тип данных как класс, методы которого являются соответствующими конструкторами и селекторами, а затем реализую все операции над членами этого класса в терминах заданных конструкторов и селекторов.

Например, возможно, Aявляется полиномиальным классом (с методами getCoefficientsи makePolynomial), который может иметь представление как SparsePoly. ] или DensePolyи B— класс комплексных чисел (с методами getReal, getImagи makeComplex) который может быть представлен как ComplexCartesianили ComplexPolar.

Ниже я воспроизвел минимальный пример. У меня есть два класса Aи B, каждый из которых имеет реализацию. Я хочу автоматически превратить все экземпляры обоих классов в экземпляры Num(для этого требуются расширения типа FlexibleInstances и UndecidableInstances ).Это прекрасно работает, когда у меня есть только один из Aили B, но когда я пытаюсь скомпилировать оба, я получаю следующую ошибку:

Duplicate instance declarations:
  instance [overlap ok] (A a, Num x, Show (a x), Eq (a x)) =>
                        Num (a x)
    -- Defined at test.hs:13:10-56
  instance [overlap ok] (B b, Num x, Show (b x), Eq (b x)) =>
                        Num (b x)
    -- Defined at test.hs:27:10-56

Я полагаю, что «дубликат экземпляра объявления, потому что тип данных может быть сделан экземпляром обоих Aи B. Я хочу иметь возможность дать обещание компилятору, что я не буду этого делать, или, возможно, указать класс по умолчанию для использования в случае, если тип является экземпляром обоих классов.

Есть ли способ сделать это (может быть, другое расширение типа?) или это то, с чем я застрял?

Вот мой код:

{-# LANGUAGE FlexibleInstances, UndecidableInstances, OverlappingInstances #-}

class A a where
    fa :: a x -> x
    ga :: x -> a x

data AImpl x = AImpl x deriving (Eq,Show)

instance A AImpl where
    fa (AImpl x) = x
    ga x = AImpl x

instance (A a, Num x, Show (a x), Eq (a x)) => Num (a x) where
    a1 + a2 = ga (fa a1 + fa a2)
    -- other implementations go here


class B b where
    fb :: b x -> x
    gb :: x -> b x

data BImpl x = BImpl x deriving (Eq,Show)

instance B BImpl where
    fb (BImpl x) = x
    gb x = BImpl x

instance (B b, Num x, Show (b x), Eq (b x)) => Num (b x) where
    -- implementations go here

Редактировать: Чтобы было ясно, я не пытаюсь писать практический код, используя эту технику. Я делаю это как упражнение, чтобы помочь себе лучше понять систему типов и расширения.

5
задан Chris Taylor 4 April 2012 в 16:11
поделиться