Неоднозначный тип с использованием параметризованных типов Haskell

У меня есть довольно простая функция, которая принимает параметризованный тип данных и возвращает тот же тип:

{-# LANGUAGE ScopedTypeVariables #-}

class IntegerAsType a where
  value :: a -> Integer

newtype (Num a, IntegerAsType n) => PolyRing a n = PolyRing [a] deriving (Eq) 

normalize :: (Num a, IntegerAsType n) => (PolyRing a n) -> (PolyRing a n)
normalize r@(PolyRing xs) | (genericLength xs) == len = r
                          | ... [other cases]
           where len = (value (undefined :: n))

Идея состоит в том, что normalize возьмет PolyRing со списком любого размера, а затем вернет новый PolyRing с дополненным/модифицированным вектором коэффициентов длины n, где n является частью типа переданного PolyRing.

Я получаю сообщение об ошибке:

Ambiguous type variable `a0' in the constraint: 
(IntegerAsType a0) arising from a use of `value'

Я просмотрел все другие сообщения SO об этой ошибке и до сих пор ничего не нашел. Ошибка возникает, даже если я удалю все ссылки на 'len' (но оставлю их в предложении where), поэтому проблема связана с

(value (undefined :: n))

что практически идентично тому, как я использовал IntegerAsType в других местах.

Пока вы этим занимаетесь, я также принимаю предложения об альтернативах системе параметризованных типов, которую я сейчас использую. В частности, это проблема, потому что мне приходится определять IntegerAsType для множества разных значений. Мы используем типы, а не параметры, чтобы гарантировать, например, что вы не можете добавить два элемента из разных колец полиномов (параметр 'a' гарантирует, что вы не сможете добавить кольца полиномов из одного и того же полинома, но над разными базовыми кольцами). ).

Спасибо


person crockeea    schedule 03.09.2011    source источник
comment
Поскольку PolyRing нигде не хранит значение типа n, единственное, что ваш клиентский код может сделать с n, — это вызвать value для неопределенного значения этого типа. Так почему у вас есть этот тип вокруг? Почему бы просто не использовать вместо этого data PolyRing a = PolyRing Integer [a], как если бы вы уже вызвали value для пользователя?   -  person Daniel Wagner    schedule 03.09.2011
comment
Вы должны удалить контекст объявления newtype. Это не имеет смысла и устарело.   -  person augustss    schedule 04.09.2011
comment
@Daniel: n представляет модуль в кольце. Не имеет смысла добавлять два элемента из разных колец, поэтому наличие 'n' гарантирует, что мы этого не сделаем. Тем не менее, может быть лучший способ сделать то же самое. Однако мы хотели бы, чтобы типы проверялись во время компиляции и во время выполнения...   -  person crockeea    schedule 04.09.2011


Ответы (1)


Подпись для normalize не создает область для переменной типа n в undefined :: n.

Попробуй это:

normalize r@(PolyRing xs :: PolyRing a n) | ... = ...
          where len = value (undefined :: n)

В качестве альтернативы вы можете использовать явный forall в сигнатуре типа для normalize:

normalize :: forall a n . (Num a, IntegerAsType n) => (PolyRing a n) -> (PolyRing a n)
normalize r@(PolyRing xs) | ... = ...
      where len = value (undefined :: n)

См. http://www.haskell.org/ghc/docs/7.0.3/html/users_guide/other-type-extensions.html#decl-type-sigs

person Lambdageek    schedule 03.09.2011
comment
Хорошо, это работает... Но, пожалуйста, объясните, почему! Поскольку я использую ScopedTypeVariables, не должна ли сигнатура типа подразумевать тип аргумента? Я хотел бы хороший учебник на этом уровне, как хорошо! - person crockeea; 03.09.2011
comment
Смотрите ссылку, которую я дал. Сигнатура типа переносит переменные типа в область видимости только в том случае, если переменные типа явно определены количественно в сигнатуре. С другой стороны, привязки шаблонов всегда переносят переменные типа в область видимости. - person Lambdageek; 03.09.2011
comment
Здесь предлагается ваше решение: hackage.haskell.org/trac/haskell-prime/ wiki/ScopedTypeVariables Но я думал, что ScopedTypeVariables будет означать, что подпись ДЕЙСТВИТЕЛЬНО создает область для 'n'. Изменить:: Спасибо за ссылку (опубликовано до вашего редактирования) - person crockeea; 03.09.2011