2014-11-20 3 views
0

В следующем коде (ideone link), почему линия (1) терпят неудачу, когда линия (4) компилирует без проблем (ideone link with line (1) commented):Необычное неоднозначным ошибка

data DataOrError a b = Error a | Data b deriving Show 

apply f (Data x) (Data y) = Data (f x y) 
apply f (Data x) [email protected](Error _) = y 
apply f [email protected](Error _) _ = x 

main = do 
    print (apply (+) x1 x2) -- (1) 
    print (apply (+) x1 e2) -- (2) 
    print (apply (+) e1 x2) -- (3) 
    print (apply (+) e1 e2) -- (4) 
    where 
    x1 = Data (2 :: Int) 
    x2 = Data (3 :: Int) 
    e1 = Error ("First thing failed") 
    e2 = Error ("Second thing failed") 

Я знаю DataOrError в основном Either, это только для иллюстрации.

Ошибка:

prog.hs:8:3: 
    No instance for (Show a0) arising from a use of `print' 
    The type variable `a0' is ambiguous 
    Possible fix: add a type signature that fixes these type variable(s) 
    Note: there are several potential instances: 
     instance (Show a, Show b) => Show (DataOrError a b) 
     -- Defined at prog.hs:1:50 
     instance Show Double -- Defined in `GHC.Float' 
     instance Show Float -- Defined in `GHC.Float' 
     ...plus 24 others 
    In a stmt of a 'do' block: print (apply (+) x1 x2) 
    In the expression: 
     do { print (apply (+) x1 x2); 
      print (apply (+) x1 e2); 
      print (apply (+) e1 x2); 
      print (apply (+) e1 e2) } 
    In an equation for `main': 
     main 
      = do { print (apply (+) x1 x2); 
       print (apply (+) x1 e2); 
       print (apply (+) e1 x2); 
       .... } 
      where 
       x1 = Data (2 :: Int) 
       x2 = Data (3 :: Int) 
       e1 = Error ("First thing failed") 
       e2 = Error ("Second thing failed") 
+0

Какая ошибка? – bheklilr

+0

Ссылка на сообщение об ошибке и ideone – Clinton

ответ

2

Вы видите ошибку, потому что полученный экземпляр для Show (DataOrError a b) выглядит

instance (Show a, Show b) => Show (DataOrError a b) where 
    ... 

Обратите внимание, что оба a и b должны быть Show экземпляры для DataOrError в имеют свой экземпляр. Тип x1 и x2 составляет DataOrError a Int, а для e1 и e2 - тип DataOrError String b. Это означает, что переменная другого типа для DataOrError не ограничена Show. Вы можете исправить это с параметрами явного типа:

main :: IO() 
main = do 
    print (apply (+) x1 x2) -- (1) 
    print (apply (+) x1 e2) -- (2) 
    print (apply (+) e1 x2) -- (3) 
    print (apply (+) e1 e2) -- (4) 
    where 
    x1 = Data 2      :: DataOrError String Int 
    x2 = Data 3      :: DataOrError String Int 
    e1 = Error "First thing failed" :: DataOrError String Int 
    e2 = Error "Second thing failed" :: DataOrError String Int 

Вы можете положить что-нибудь там, в том числе (), для переменной типа вы не используете так долго, как это экземпляр Show. Единственная причина, почему это происходит, заключается в том, что компилятор пытается быть полезным и выводит, что параметр, который вы не указали, является более общим, чем вы на самом деле хотите. Хотя вы можете сказать, что это не имеет значения, компилятор не смотрит на значения, чтобы определить, можно ли что-то печатать, он смотрит на типы.

Причина, по которой вы не видите ошибку в строке 4, но вы делаете в строке 1 из-за дефолта. Для строк 2 и 3 он может определить полный тип возвращаемого значения apply (+), но в строке 4 компилятор знает только, что он должен быть Num a. Затем он выбирает значение по умолчанию Integer, которое я неправильно интерпретировал сначала как ошибку, потому что всегда компилирую с предупреждениями как ошибки.

+0

Итак, почему строка (4) компилируется без проблем и не (1)? Фактически выполнение вашего предложения с помощью только 'x1' устраняет проблему,' e1' и 'e2' работают без проблем. – Clinton

+0

@Clinton Выдает мне ошибку. Какую версию GHC вы используете? – bheklilr

+0

http://ideone.com/vqfZko работает отлично – Clinton

Смежные вопросы