如何在haskell中实现withFile

时间:2011-12-19 20:21:35

标签: haskell

haskell tutorial之后,作者提供了 withFile 方法的以下实现:

withFile' :: FilePath -> IOMode -> (Handle -> IO a) -> IO a  
withFile' path mode f = do  
    handle <- openFile path mode   
    result <- f handle  
    hClose handle  
    return result  

但为什么我们需要将result包裹在return中?提供的函数f是否已经返回IO,因为它的类型Handle -> IO a可以看到它?

2 个答案:

答案 0 :(得分:7)

你是对的:f已经返回IO,所以如果函数是这样写的:

withFile' path mode f = do  
    handle <- openFile path mode   
    f handle

没有必要返回。问题是hClose handle介于两者之间,所以我们必须先存储结果:

result <- f handle

并且<-正在摆脱IO。所以return会把它放回去。

答案 1 :(得分:3)

这是我第一次尝试使用Haskell时困扰我的一件小事。你在误写中误解了<-结构的含义。 result <- f handle并不代表&#34;将f handle的值分配给result&#34 ;;它意味着&#34;将result绑定到一个值&#39;提取&#39;来自f handle&#34;的monadic值(&#39;提取&#39;以某种方式发生,由您正在使用的特定Monad实例定义,在本例中为IO monad)。

即,对于某些Monad类型类m,<-语句在右侧使用类型m a的表达式,在左侧使用类型a的变量,将变量绑定到一个值。因此,在您的特定示例中,使用result <- f handle,我们有f result :: IO aresult :: areturn result :: IO a类型。

PS do-notation还有let的特殊形式(在这种情况下没有in关键字!),作为<-的纯对应物。所以你可以将你的例子重写为:

withFile' :: FilePath -> IOMode -> (Handle -> IO a) -> IO a  
withFile' path mode f = do  
    handle <- openFile path mode   
    let result = f handle  
    hClose handle  
    result

在这种情况下,由于let是一项简单的分配,因此result的类型为IO a