Почему эта переменная типа неоднозначна? - PullRequest
6 голосов
/ 03 апреля 2009

Cabbage.hs:

module Cabbage where 
class Cabbage a
  where foo :: a -> String      -- the parameter is only present for its type,
                                -- the parameter value will be ignored
        bar :: String -> a
quux :: Cabbage a => String -> a
quux s = bar (s ++ foo (undefined :: a))

Когда я компилирую (с ghc), я получаю это сообщение об ошибке:

Cabbage.hs:7:19:
    Ambiguous type variable `a' in the constraint:
      `Cabbage a' arising from a use of `foo' at Cabbage.hs:7:19-38
    Probable fix: add a type signature that fixes these type variable(s)

Я не понимаю, почему a неоднозначно. Конечно, a в строке 7 совпадает с a в строке 6? Как мне это исправить?

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

Ответы [ 3 ]

11 голосов
/ 03 апреля 2009

Используя переменные типа scoped, вы можете сообщить GHC, что undefined :: a должно быть одинаковым (в противном случае a - это просто сокращение для forall a. a). Переменные типа Scoped должны быть явно квалифицированы полностью:

{-# LANGUAGE ScopedTypeVariables #-}
module Cabbage where 
class Cabbage a
  where foo :: a -> String      -- the parameter is only present for its type,
                                -- the parameter value will be ignored
        bar :: String -> a
quux :: forall a. Cabbage a => String -> a
quux s = bar (s ++ foo (undefined :: a))
2 голосов
/ 04 апреля 2009

вы можете извлечь полиморфную часть как функцию

quux :: Cabbage a => String -> a
quux s = quux' undefined
    where quux' :: Cabbage a => a -> a
          quux' x = bar (s ++ foo x)
2 голосов
/ 03 апреля 2009

Проблема в том, что Haskell не знает, какому экземпляру Cabbage соответствует foo. Насколько я знаю, это не соответствует a в (undefined :: a) с a в quux :: Cabbage a => String -> a

Предполагая, что это то, что вы хотите, вы можете сделать это:

quux :: Cabbage a => String -> a
quux s = result
    where result = bar (s ++ foo result)

Это связывает foo и bar вместе, так что он использует один и тот же экземпляр для обоих, и, так как вам на самом деле не нужно значение ввода для foo, оно заканчивается. Хотя я не знаю лучшего способа создания констант для каждого экземпляра. Надеюсь, придет кто-то еще, кто это сделает.

...