Вопрос

Капуста.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?Как мне это исправить?

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

Это было полезно?

Решение

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

{-# 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))

Другие советы

Проблема в том, что 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, оно достигает минимума.Однако я не знаю лучшего способа создания констант для каждого экземпляра.Надеюсь, появится кто-нибудь еще, кто это сделает.

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

quux :: Cabbage a => String -> a
quux s = quux' undefined
    where quux' :: Cabbage a => a -> a
          quux' x = bar (s ++ foo x)
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top