为什么返回类型多态中的Haskell推断类型会导致运行时错误?

haw*_*eye 0 polymorphism haskell clojure

我选择使用Haskell的原因在于其丰富的类型系统.这在编译时为我提供了有关我的程序的更多信息,帮助我确信它是合理的.

此外,Haskell似乎是一种处理表达式问题的最佳语言,因为Haskell类型类可以在返回类型上进行调度.(与Clojure协议相反 - 它只能在第一个参数上调度).

当我探索Haskell多态返回值函数时read:

read :: (Read a) => String -> a
Run Code Online (Sandbox Code Playgroud)

使用以下程序:

addFive :: Int -> Int
addFive x = x + 5

main :: IO ()
main = do
    print (addFive (read "11"))
    putStrLn (read "11")
Run Code Online (Sandbox Code Playgroud)

我得到以下结果:

Runtime error
...
prog: Prelude.read: no parse
Run Code Online (Sandbox Code Playgroud)

所以我似乎在使用高级类型系统的语言中获得运行时错误.

将其与Clojure中的等效代码进行对比:

(defn add-five [x] (+ 5 x))

(println (add-five (read-string "11")))
(println (read-string "11"))
Run Code Online (Sandbox Code Playgroud)

这给出了以下结果:

16
11
Run Code Online (Sandbox Code Playgroud)

我的问题是为什么Haskell在返回类型多态中推断类型会导致运行时错误?不应该在编译时把它们拿起来吗?

Cir*_*dec 5

该运行时错误与多态无关,而且与该"11"函数无法将字符串解析为字符列表这一事实有关read.

这是有用的东西.请注意"11",在运行时,可以将其解析为a,Int并且"\"Some More String\""可以在运行时将其解析为字符串.

print $ 5 + read "11"
print $ "Some string" ++ read "\"Some More String\""
Run Code Online (Sandbox Code Playgroud)

以下是一些不起作用的事情.他们不工作,因为"Not an integer"不能被解析为Int"11"不能被解析为一个字符串.

print $ 5 + read "Not an integer"
print $ "Some string" ++ read "11"
Run Code Online (Sandbox Code Playgroud)

正如您在上一个问题答案中指出的那样,类型信息已在编译时推断出来.该read功能已经被选定.试想一下,如果我们有两个功能readInt :: String -> Int,并readString :: String -> String得以提供的read功能为Read对实例IntString分别.在编译时,编译器已经read用原始的相应函数替换了出现的情况:

print $ 5 + readInt "Not an integer"
print $ "Some string" ++ readString "11"
Run Code Online (Sandbox Code Playgroud)

这必须在编译时发生,因为在编译时消除了类型信息,正如您在上一个问题的答案中所解释的那样.