Haskell 中的每个函数都返回一个特定类型的值。
在这种情况下,doubleMe 函数返回一个 Int 类型的值。当您从 ghci 解释器加载文件时,它会加载文件中的所有函数并使它们可供您使用。
main 函数是一个稍微特殊的函数,与其他语言很像。它定义了 Haskell 程序的入口点。然而,由于它只是另一个 Haskell 函数,它也必须返回一个特定类型的值。 main 函数被限制为返回 IO 类型的值,最常见的是 IO ()。
IO 本身也很特别,属于一类叫做 monads 的类型。你可以阅读IO monad here.
现在让我们回到您的代码:
main = do
doubleMe 2
暂时忽略do 语法。您基本上是在告诉编译器main 函数返回doubleMe 2,它的类型为Int。这不会飞。 main 已经返回一个 IO 类型的值。在这种情况下,您可以使用return 函数将Int 值转换为IO Int 值。 (return 函数是所有 monadic 类型必须具有的函数。很简单地说,它将任何类型的值转换为 monadic 值。)
这样就变成了:
main = do
return (doubleMe 2)
这是完全有效的代码,并且可以编译。然而,一旦你运行这个程序,你会发现它什么也没做。这是因为程序返回值 4。
其实不用do也可以写,就变成了:
main = return (doubleMe 2)
这也行。
但是,让我们假设您要打印出该值。这就是IO 真正发挥作用的地方。打印到屏幕是IO 操作。
main = do
print (doubleMe 2)
return (doubleMe 2)
do 表达式允许您链接一组IO 操作。所以你的程序仍然会返回值4,但它会首先计算表达式print (doubleMe 2)。正如预期的那样,这实际上会导致打印值doubleMe 2。
检查 ghci 中的 print 函数。
> :t print
print :: Show a => a -> IO ()
打印函数作用于可以显示的任何类型的值,它会导致IO 操作(打印到屏幕)但不返回任何()。
所有这些示例都有效,希望能让事情变得更清楚。 (查看main 的类型签名)。
-- main :: IO Int
main = return (doubleMe 2)
-- main :: IO Int
main = do
print (doubleMe 2)
return (doubleMe 2)
-- main :: IO ()
main = do
print (doubleMe 2)
return ()
-- main :: IO ()
main = do
print (doubleMe 2)
-- main :: IO ()
main = print (doubleMe 2)
-- main :: IO ()
main = do
print "Hello"
print (doubleMe 2)
return ()
-- main :: IO String
main = do
print "Hello"
print (doubleMe 2)
return "Hello"