在 haskell 程序中有两种不同的使用方式IO
,例如:
main :: IO ()
-- and
readLine :: IO Int
这两者有什么区别?
IO ()
并且IO Int
从根本上非常相似。 Int
并且()
都是 Haskell 中的两种类型。 ()
仅在它只有一个值(也用 表示()
)的意义上是特殊的,所以我们从来没有真正对它感兴趣。
唯一的区别是它们的返回值。 main
返回一个类型的值,()
你的readLine
返回一个Int
. 也许这个例子会有所帮助:
main = do
x <- putStrLn "Test"
print x
当你运行它时,它会输出:
>>> main
Test
()
print 语句打印 a()
因为那是 的返回值putStrLn
:
putStrLn :: String -> IO ()
您通常不绑定类似返回值的原因是这样做不会putStrLn
获得任何信息,因为()
无论如何它总是返回。
IO Int
意思是:这是一个 IO 动作,它return
是一个 Int。
IO ()
意思是:这是一个不返回任何有意义结果的 IO 操作。(如main
。)
IO ()
是可以执行以提取 type 值的操作的类型()
。type 只有一个(非底部)值()
,它也是拼写的()
(您可以通过知道您是在查看类型表达式还是值表达式来区分它们,就像以大写字母开头的名称是类型构造函数一样或数据构造函数,具体取决于您查看的是类型表达式还是值表达式)。由于只有一个(非底部)值,因此该值绝对不会告诉您任何信息(严格来说,它至少告诉您计算确实成功终止,仅此而已)。所以IO ()
通常用作我们只对它们的副作用感兴趣的 IO 操作类型。
putStrLn "Hello World"
是类型值的示例IO ()
。它根本不计算任何有趣的东西。将字符串写入终端产生的值是多少?获取()
它的执行时间只会告诉我们它确实执行了。
IO Int
是可以执行以提取 type 值的操作的类型Int
。与所有 IO 动作一样,它究竟做了什么会对程序之外的世界产生影响和影响;Haskell 对他们一无所知。但它确实知道执行该操作将产生一个 Haskell 类型的值Int
,不管它可能做什么。
readLn :: IO Int
是类型值的一个示例IO Int
(类型注释作为独立表达式是必要的,以避免歧义;在更广泛的上下文中,您实际使用从readLn
某些Int
特定操作中提取的值,您可能会不使用它)。与将字符串写入终端不同,从终端读取字符串并将其转换为 anInt
确实会产生一个值。
更普遍IO
的是可以应用于任何类型的类型构造函数;IO a
是可以执行的执行类型,并会产生 type 的值a
。以上两者都只是其中的例子;两者都没有特别处理。()
是一个完全普通的类型,并且()
是该类型的一个完全普通的值,但是因为这些值不传达任何信息(除了“此计算成功终止”),您通常不会看到()
它自己;它往往只与应用的类型构造函数一起使用,例如 in IO ()
,用于我们只关心类型构造函数添加的结构的值,而不关心它“内部”的值。