Почему Haskell не может вывести этот тип

Я пытался написать программу для реализации полиномов в произвольном поле, математической структуре. В качестве языка программирования я выбрал Haskell и использовал расширение языка GADTs. Однако я не понимаю, почему GHCi не может вывести ограничения a.

Контекст:

-- irreducible.hs

{-# LANGUAGE GADTs #-}

infixl 6 .+
infixl 7 .*

class Ring a where
  (.+) :: a -> a -> a
  (.*) :: a -> a -> a
  fneg :: a -> a
  fzero :: a
  funit :: a

class (Ring a) => Field a where
  finv :: a -> a

data Polynomial a where 
  Polynomial :: (Field a) => [a] -> Char -> Polynomial a

instance (Show a) => Show (Polynomial a) where
  show (Polynomial (a0:ar) x)
    = show a0
      ++ concatMap (\(a, k) -> "+" ++ show a ++ x:'^':show k) (zip ar [0..])
  show (Polynomial [] _) = show (fzero::a)

Объяснение: Кольцо — это что-то с определенными сложением и умножением, где сложение образует (фактически абелеву) группу, а умножение образует моноид. Поле — это кольцо с заданным обратным умножением. Полиномы в поле представлены списком коэффициентов и символом. Символ, например 'x', указывает, что этот полином относится к неизвестной переменной x. Для нулевого полинома, который записывается как Polynomial [] 'x', я хочу, чтобы он показывал нулевой элемент базового поля.

После запуска на GHCi я получил это:

irreducible.hs:59:28: error:
    • Could not deduce (Show a0) arising from a use of ‘show’
      from the context: Show a
        bound by the instance declaration at irreducible.hs:55:10-40
      or from: Field a
        bound by a pattern with constructor:
                   Polynomial :: forall a. Field a => [a] -> Char -> Polynomial a,
                 in an equation for ‘show’
        at irreducible.hs:59:9-23
      The type variable ‘a0’ is ambiguous
      These potential instances exist:
        instance (Show a, Show b) => Show (Either a b)
          -- Defined in ‘Data.Either’
        instance Show Ordering -- Defined in ‘GHC.Show’
        instance Show Integer -- Defined in ‘GHC.Show’
        ...plus 25 others
        ...plus 87 instances involving out-of-scope types
        (use -fprint-potential-instances to see them all)
    • In the expression: show (fzero :: a)
      In an equation for ‘show’:
          show (Polynomial [] _) = show (fzero :: a)
      In the instance declaration for ‘Show (Polynomial a)’
   |
59 |   show (Polynomial [] _) = show (fzero::a)
   |                            ^^^^^^^^^^^^^^^

irreducible.hs:59:34: error:
    • Could not deduce (Ring a1) arising from a use of ‘fzero’
      from the context: Show a
        bound by the instance declaration at irreducible.hs:55:10-40
      or from: Field a
        bound by a pattern with constructor:
                   Polynomial :: forall a. Field a => [a] -> Char -> Polynomial a,
                 in an equation for ‘show’
        at irreducible.hs:59:9-23
      Possible fix:
        add (Ring a1) to the context of
          an expression type signature:
            forall a1. a1
    • In the first argument of ‘show’, namely ‘(fzero :: a)’
      In the expression: show (fzero :: a)
      In an equation for ‘show’:
          show (Polynomial [] _) = show (fzero :: a)
   |
59 |   show (Polynomial [] _) = show (fzero::a)
   |            

Теперь давайте сосредоточимся на сомнительной части:

instance (Show a) => Show (Polynomial a) where
  show (Polynomial (a0:ar) x) = show a0 ++ [...]
  show (Polynomial [] _) = show (fzero::a)

На мой взгляд, Polynomial a гарантирует, что a является экземпляром Field, что подразумевает, что a является экземпляром Ring. Поэтому вызов fzero::a, как и 42::Int, должен быть разумным. Кроме того, я уже написал Show a в качестве ограничения, а конструктор Polynomial a имеет форму Polynomial [a] Char, поэтому он также должен знать, что тип a0 является экземпляром Show.

Видимо, интерпретатор думает иначе. Где я сделал ошибку?


person fantasie    schedule 05.05.2019    source источник
comment
Распространенная ошибка, ищите ScopedTypeVariables.   -  person arrowd    schedule 05.05.2019
comment
@arrowd Спасибо! Это подходит для меня.   -  person fantasie    schedule 05.05.2019


Ответы (1)


Из комментария стрелка:

Код в порядке, но требует расширения ScopedTypeVariables, что делает переменную типа a в fzero :: a ссылкой на ранее введенное a.

person Community    schedule 05.05.2019