"Ambigous type variable" error when defining custom "read" function
While trying to compile the following code, which is enhanced version of read build on readMay from 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)
I get an error from GHC:
WavefrontSimple.hs:54:81:
Ambiguous type variable `a' in the constraint: `Typeable a' arising from a use of `typeOf' at src/WavefrontSimple.hs:54:81-103 Probable fix: add a type signature that fixes these type variable(s)`
I don't understand why. What should be fixed to get what I meant?
EDIT: Ok, so the solution to use ScopedTypeVariables
and forall a
in type signature works. But why the following produces very similar error to the one above? The compiler should infer the right type since there 开发者_如何转开发is asTypeOf :: a -> a -> a
used.
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)
The latter doesn't work because the type of xx
is the same as the type of undefined
-- i.e., "forall a. a." The fact that you force xx to be used with one concrete type with the asTypeOf operator doesn't mean that it is less polymorphic everywhere else.
The a
in undefined :: a
and readI :: (Typeable a, Read a) => String -> a
are not the same type a
. It's as if you wrote readI :: ... a; readI = ... (undefined :: b)
.
{-# LANGUAGE ScopedTypeVariables #-}
readI :: forall a. (Typeable a, Read a) => String -> a
...
The scoped type variables extension changes the Haskell language to allow you to carry the type variable a
from outer scope to inner scope, if explicitly quantified with forall
.
I'm not sure why your x `asTypeOf` xx
doesn't seem to work. This does, though:
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)
I think you need scoped type variables.
{-# 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)
See also.
精彩评论