`print`和`withFile`的不同返回类型

时间:2014-06-17 02:19:15

标签: haskell

Haskell withFile打开一个给定IOMode的文件,然后应用函数Handle -> IO r。最终,它返回一个类型IO r

Prelude> import System.IO

Prelude System.IO> :t withFile
withFile :: FilePath -> IOMode -> (Handle -> IO r) -> IO r

print获取导出a的{​​{1}},然后返回Show类型。

IO ()

Prelude System.IO> :t print print :: Show a => a -> IO () IO r之间的显着差异是什么?

3 个答案:

答案 0 :(得分:5)

IO是一种类型* -> *,也就是说它需要一个类型参数。通常,IO表示可以执行I / O并产生结果的monadic动作。给IO的类型参数确定结果的类型。因此,

  1. IO ()是一个可以执行I / O并产生()的monadic操作。 A ()只有一个值,所以它没有传达任何信息。由于它不传达任何信息,因此通常使用void作为传统过程编程语言中的返回值的方式使用它。

  2. IO r是一个可以执行I / O并生成r的monadic操作。您可能会注意到与上述语句的相似之处。区别在于,()不是像r这样的具体类型,而是类型变量

  3. 让我详细说明这意味着什么及其后果。查看id的类型:

    ghci> :t id
    id :: a -> a
    

    这当然意味着如果id被赋予a类型的参数,它将返回相同类型a的结果。现在检查const ()的类型:

    ghci> :t const ()
    const () :: a -> ()
    

    如果我们给它a,它将返回()类型的结果。现在检查error

    ghci> :t error
    error :: String -> a
    

    我们必须给它一个String,但它的返回值可以适应我们需要的任何东西。当然,因为我们不一定能构造任何给定类型的值,这意味着唯一可能的定义是从不返回一个值,这是error所做的。

    因此,有了这种理解,您应该意识到虽然IO r总是意味着“可以执行I / O并返回类型r的值的monadic动作”,但其含义可能会有所不同,具体取决于在类型签名中出现的位置。让我们看看你的具体例子:

    ghci> :t withFile
    withFile :: FilePath -> IOMode -> (Handle -> IO r) -> IO r
    

    如果我们有一个函数返回IO r而其他地方没有出现r,我们可以得出的唯一结论是IO必须永远不会产生值,否则我们无法声称它可以返回任意r。幸运的是,情况并非如此:确实出现了另一个rwithFile采用返回IO r的函数。由于withFile会产生IO来创建r,并且它知道如何创建r的唯一方法是通过我们提供的函数,我们知道如果它是要终止,它必须至少执行一次我们给它的功能。此外,我们知道它必须返回其中的一个r

    因此,在withFile的上下文中,IO r意味着如果你给它一个函数产生一个返回某个特定类型的monadic动作,withFile最终会给你一个产生这种类型的monadic动作也是如此。作为一个具体的例子:

    myInt <- withFile "number.txt" ReadMode (fmap read . hGetContents)
    print (myInt + (1 :: Int))
    

    hGetContents,如果Handle,将返回IO Stringfmap read会将其转换为IO Int。由于withFile是使用类型变量定义的,未指定任何特定的具体类型,因此它将适应我们提供的类型(Handle -> IO Int)并返回IO Int。然后我们可以在<-符号块中使用do来执行它并将myInt绑定到结果。返回值通过withFile冒充。

答案 1 :(得分:2)

IO r表示在执行具有副作用的操作后,其中将包含一些值r

结果类型为IO

()次操作可与其他语言的void进行比较。 (实际上它是一个空元组(),其类型也是())。

IO rIO ()之间的区别在于,在执行具有副作用的操作后的第二种情况下,它不包含任何值。这表示您正在执行IO操作,其唯一目的是打印到屏幕等副作用。而在IO r中,在执行具有副作用的操作后,它还包含一些包含在IO中的值,该值随后可以在您的程序中使用。


即使withFile函数也可以返回IO (),因为r只是()的更一般形式,具体取决于传递给它的高阶函数的类型:

test = withFile "testFile" ReadMode (\handle ->
                                           do
                                             str <- hGetContents handle
                                             print str
                                           )

检查其类型:

ghci> :t test
test :: IO ()

答案 2 :(得分:0)

IO r是一种更通用的类型,然后是IO ()

r是一个变量,可以是任何类型。

如果r == (),则IO r == IO ()