GHC Перекрывающиеся случаи при обобщении сложения

Пытаясь обобщить (+) больше, чем просто Nums, я написал до Addable учебный класс:

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

class Addable a where
  (+) :: Addable a => a -> a -> a

instance Addable [a] where
  (+) = (++)

instance Num a => Addable a where
  (+) = (Prelude.+)

При попытке добавить (объединить) списки, GHC жалуется на перекрывающиеся экземпляры:

*Test> "abc" + "defghi"

<interactive>:84:7:
    Overlapping instances for Addable [Char] arising from a use of `+'
    Matching instances:
      instance Num a => Addable a -- Defined at Utils.hs:23:10
      instance Addable [a] -- Defined at Utils.hs:20:10
    In the expression: "abc" + "defghi"
    In an equation for `it': it = "abc" + "defghi"

Я знаю, что GHC игнорирует контекст при выборе экземпляров классов типов, поэтому стараюсь выбирать между Addable [a] а также Addable a это действительно проблема. Однако я ожидаю, что GHC выберет первое определение, поскольку оно более конкретное. Почему этого не происходит?

Кроме того, есть ли элегантный способ решения этой проблемы? Или я иду на это с неправильной точки зрения?

1 ответ

Решение

Вам нужно включить перекрывающиеся экземпляры, чтобы фактически использовать их. В более старых версиях компилятора вы могли сделать это для каждого модуля с помощью OverlappingInstances расширение:

{-# LANGUAGE OverlappingInstances #-}

Это работает правильно для этого кода:

λ> :set -XOverlappingInstances
λ> "abc" + "def"
"abcdef"

Однако этот подход не рекомендуется в более новых версиях GHC (по крайней мере, в 8.0):

Misc.hs:1:73-92: warning: …
    -XOverlappingInstances is deprecated: 
      instead use per-instance pragmas OVERLAPPING/OVERLAPPABLE/OVERLAPS

Таким образом, более современный подход состоит в том, чтобы указать это для каждого отдельного экземпляра:

instance {-# OVERLAPPABLE #-} Num a => Addable a where
  (+) = (Prelude.+)

Этот стиль прагмы также существует для OVERLAPPING, OVERLAPS а также INCOHERENT, позволяя вам аннотировать конкретные экземпляры с этими свойствами.

Другие вопросы по тегам