Ошибка переменной неоднозначного типа при определении пользовательской функции чтения

При попытке скомпилировать следующий код, который представляет собой расширенную версию сборки readMay из Safe package.

readI :: (Typeable a, Read a) => String -> a
readI str = case readMay str of
               Just x -> x 
               Nothing -> error ("Prelude.read failed, expected type: " ++ 
                                 (show (typeOf > (undefined :: a))) ++ 
                                 "String was: " ++ str)

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

WavefrontSimple.hs: 54: 81:
Переменная неоднозначного типа `a 'в ограничении:
` Typeable a'
возникающая в результате использования `typeOf 'в src / WavefrontSimple.hs: 54: 81- 103
Возможное исправление: добавьте сигнатуру типа, которая исправляет эти переменные типа `

Не понимаю почему. Что нужно исправить, чтобы получить то, что я имел в виду?

РЕДАКТИРОВАТЬ: Итак, решение использовать ScopedTypeVariables и forall a в сигнатуре типа работает. Но почему следующее приводит к ошибке, очень похожей на ошибку выше? Компилятор должен определить правильный тип, поскольку используется asTypeOf :: a -> a -> a.

readI :: (Typeable a, Read a) => String -> a
readI str = let xx = undefined in
            case readMay str of
              Just x -> x `asTypeOf` xx
              Nothing -> error ("Prelude.read failed, expected type: " 
                               ++ (show (typeOf xx)) ++ 
                                "String was: " ++ str)

person Tener    schedule 24.03.2010    source источник
comment
Я проголосовал за закрытие как дурацкий перед редактированием. Теперь, когда вопрос был обновлен, я считаю, что это больше не дубликат, но не могу удалить VTC. Думаю, мне просто нужно подождать, пока он истечет сам по себе.   -  person ephemient    schedule 26.03.2010


Ответы (3)


Последнее не работает, потому что тип xx совпадает с типом undefined, то есть «forall a. A. A.». Тот факт, что вы заставляете xx использоваться с одним конкретным типом с помощью оператора asTypeOf, не означает, что он менее полиморфен везде.

person sclv    schedule 24.02.2011
comment
Я считаю, что ты прав. Мое понимание до вашего объяснения было немного другим, и я все же должен изменить свое мышление. - person Tener; 02.03.2011

a в undefined :: a и readI :: (Typeable a, Read a) => String -> a - это разные типы a. Вы как будто написали readI :: ... a; readI = ... (undefined :: b).

{-# LANGUAGE ScopedTypeVariables #-}

readI :: forall a. (Typeable a, Read a) => String -> a
...

Переменные типа с областью видимости расширение изменяет язык Haskell, позволяя вам переносить переменную типа a из внешней области во внутреннюю, если это явно количественно выражено с помощью forall.


Я не уверен, почему ваш x `asTypeOf` xx не работает. Однако это действительно так:

readI :: (Typeable a, Read a) => String -> a
readI str = xx where
    xx = case readMay str of
             Just x -> x
             Nothing -> error ("Prelude.read failed, expected type: "
                              ++ (show (typeOf xx)) ++
                               "String was: " ++ str)
person ephemient    schedule 24.03.2010
comment
Этот вопрос может быть обманом, но это лучшее объяснение, которое я видел до сих пор. - person Nathan Shively-Sanders; 25.03.2010

Я думаю, вам нужны переменные с ограниченным типом.

{-# LANGUAGE ScopedTypeVariables #-}
readI :: forall a. (Typeable a, Read a) => String -> a
readI str = case readMay str of
               Just x -> x 
               Nothing -> error ("Prelude.read failed, expected type: " ++ 
                                 (show (typeOf > (undefined :: a))) ++ 
                                 "String was: " ++ str)

См. также.

person dave4420    schedule 24.03.2010
comment
Упс, мне следовало сначала поискать дубликаты. Это, очевидно, один. - person ephemient; 25.03.2010
comment
Я действительно искал дубликаты, видимо, недостаточно усердно. Виноват. - person Tener; 25.03.2010