Что означает эта «переменная неоднозначного типа« a »в ограничении»?

В этом коде я пытаюсь сделать так, чтобы первый параметр в моей рабочей функции go был типом «семейство типов». Я вижу, что в документации семейств типов аналогичная функция insert принадлежит классу типов, а в моем примере ниже это не.

Я новичок в типах семейств, поэтому, возможно, я их неправильно использую, но что означает эта ошибка?

{-# LANGUAGE TypeFamilies #-}

-- | key
class K a where
  -- | iterator for key
  type I a :: *
  mkI :: a -> I a

--| A map
data (K a) => M a b = M a b

insert :: (K a) => a -> b -> M a b -> M a b
insert = go mkI    -- <<< PROBLEM
  where
    go o a b m = m

Переменная неоднозначного типа `a 'в ограничении:

`K a'

  arising from an expression type signature at Data/Map2.hs:167:10-33

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


person user239558    schedule 11.01.2012    source источник
comment
Прежде всего, обратите внимание, что контексты типов данных (data (K a) => M a b = M a b) были удалены из языка и никогда не были полезными. Смотрю сейчас на другие вещи.   -  person Daniel Fischer    schedule 12.01.2012


Ответы (1)


Это компилирует:

{-# LANGUAGE TypeFamilies, GADTs, ScopedTypeVariables #-}

-- | key
class K a where
  -- | iterator for key
  type I a :: *
  mkI :: a -> I a

-- | A map
data M x y where
    M :: K a => a -> b -> M a b

insert :: forall a b. (K a) => a -> b -> M a b -> M a b
insert = go mkI
  where
    go :: (a -> I a) -> a -> b -> M a b -> M a b
    go o a b m = m

Что я изменил и почему?

Во-первых, я предположил, что вам нужно ограничение на M, поэтому я использовал форму определения типа, которая обеспечивает соблюдение ограничения и делает его доступным на сайтах использования, a GADT.

Во-вторых, проблема, на которую жаловался ваш GHC, неоднозначность. Дело в том, что компилятор не может определить, какой mkI он должен использовать, поэтому мы должны сообщить об этом. Для этого мы должны перенести используемые переменные типа в область видимости, а затем сообщить компилятору в локальной сигнатуре, какой экземпляр типа использовать.

person Daniel Fischer    schedule 11.01.2012
comment
Здравствуйте, как бы вы сделали функцию верхнего уровня? - person cdupont; 03.08.2016
comment
@cdupont Вы можете просто переместить его на верхний уровень и добавить ограничение к сигнатуре типа go :: (K a) => (a -> I a) -> a -> b -> M a b -> M a b. Однако я не понимаю, для чего это может быть полезно. - person Daniel Fischer; 03.08.2016
comment
В этом случае a и b в insert будут разными в _4 _... Это причина, по которой вы добавили forall no? - person cdupont; 03.08.2016
comment
@cdupont Аргументы, переданные от insert, будут определять используемые типы a и b. forall необходим для обозначения этих типов в рамках insert. На верхнем уровне типы в сигнатуре типа не зависят от типов insert, но передача аргументов гарантирует, что вызываемый экземпляр go использует те же типы. - person Daniel Fischer; 03.08.2016