为何fromInteger可返回多态值而read不行?兼论编译与GHCI差异
Haskell类型类多态行为疑问
1. 为何fromInteger能返回多态值,而read不行?
先查看两个函数的类型签名:
λ> :t fromInteger fromInteger :: Num a => Integer -> a λ> :t read read :: Read a => String -> a
在GHCI中测试fromInteger的行为:
λ> fromInteger(42::Integer) 42 λ> :t it it :: Num a => a λ> :t fromInteger(42::Integer) fromInteger(42::Integer) :: Num a => a λ> :t 42 42 :: Num p => p
但测试read时会直接抛出异常:
λ> read "2" *** Exception: Prelude.read: no parse λ> :t read "2" read "2" :: Read a => a λ> z = read "2" λ> z *** Exception: Prelude.read: no parse λ> :t z z :: Read a => a
编译阶段read会直接报错,而fromInteger可正常通过检查:
测试代码:
trial0 = read ("2"::String) trial2 = fromInteger(2::Integer)
编译错误信息:
• Ambiguous type variable ‘a0’ arising from a use of ‘read’ prevents the constraint ‘(Read a0)’ from being solved. Relevant bindings include trial0 :: a0 (bound at /Users/maatari/Dev/IdeaProjects/haskell-from-first-principles/basic-datatypes/src/LearningBasicDataTypes.hs:174:1) Probable fix: use a type annotation to specify what ‘a0’ should be. These potential instances exist: instance (Read a, Read b) => Read (Either a b) -- Defined in ‘Data.Either’ instance Read Ordering -- Defined in ‘GHC.Read’ instance Read Integer -- Defined in ‘GHC.Read’ ...plus 23 others ...plus 35 instances involving out-of-scope types (use -fprint-potential-instances to see them all) • In the expression: read ("2" :: String) In an equation for ‘trial0’: trial0 = read ("2" :: String) | 174 | trial0 = read ("2"::String) | ^^^^^^^^^^^^^^^^^^ Failed, no modules loaded.
2. 如何解释编译阶段与GHCI中的行为差异?
GHCI似乎会默认选择一个类型类实例,导致read执行失败;但编译时不接受这种类型歧义,无法返回多态值。然而fromInteger无论在GHCI还是编译检查中都能返回多态值。
Edit 1:自定义类型类复现read行为
自定义测试代码:
data Mood = Blah | Woot deriving (Show) class Pretty a where pretty :: String -> a instance Pretty Integer where pretty x = read x instance Pretty Double where pretty x = read x instance Pretty Mood where pretty x = Blah
GHCI中的行为
λ> pretty "2" 2 λ> pretty "2.0" *** Exception: Prelude.read: no parse λ> pretty "x" *** Exception: Prelude.read: no parse λ>
这里的行为是GHCI默认选择了Pretty Integer实例,因此第一个调用成功,后两个失败。添加类型注解后可以明确指定要使用的实例:
λ> pretty "2.0" :: Double 2.0 λ> pretty "x" :: Double *** Exception: Prelude.read: no parse λ> pretty "x" :: Mood Blah λ>
编译阶段的行为
测试代码:
trial = pretty "2"
编译错误信息:
• Ambiguous type variable ‘a0’ arising from a use of ‘pretty’ prevents the constraint ‘(Pretty a0)’ from being solved. Relevant bindings include trial :: a0 (bound at /Users/maatari/Dev/IdeaProjects/haskell-from-first-principles/basic-datatypes/src/LearningBasicDataTypes.hs:178:1) Probable fix: use a type annotation to specify what ‘a0’ should be. These potential instances exist: instance Pretty Integer -- Defined at /Users/maatari/Dev/IdeaProjects/haskell-from-first-principles/basic-datatypes/src/LearningBasicDataTypes.hs:163:10 instance Pretty Mood -- Defined at /Users/maatari/Dev/IdeaProjects/haskell-from-first-principles/basic-datatypes/src/LearningBasicDataTypes.hs:169:10 instance Pretty Double -- Defined at /Users/maatari/Dev/IdeaProjects/haskell-from-first-principles/basic-datatypes/src/LearningBasicDataTypes.hs:166:10 • In the expression: pretty "2" In an equation for ‘trial’: trial = pretty "2" | 178 | trial = pretty "2" | ^^^^^^^^^^ Failed, no modules loaded.
内容的提问来源于stack exchange,提问作者MaatDeamon
相关产品推荐
相关产品推荐

