2011-12-19 43 views
5

haskell tutorial實現,筆者提供了以下實施withFile方法:如何withFile在Haskell

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

,但爲什麼我們需要包裝的resultreturn?提供的功能f是否已返回IO,如其類型Handle -> IO a所示?

回答

7

你說得對:f已經返回IO,因此,如果功能均寫成這樣:

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

就沒有必要了一回。問題是hClose handle進來之間,所以我們必須先存儲結果:

result <- f handle 

,做<-擺脫了IO的。所以return把它放回去。

+0

哦,哦!完全錯過了_sucking_'<-'操作符! – drozzy 2011-12-19 20:26:03

+1

它也可以'讓結果= f處理; h關閉手柄;結果「還是我再次失敗monad理解? – delnan 2011-12-19 20:44:58

+3

@delnan that would'do {handle < - openFile mode path; h關閉手柄; f把手; }',所以'f handle'可能會抱怨關閉的句柄。 – 2011-12-19 20:55:15

3

這是當我第一次嘗試Haskell時讓我困惑的棘手小事之一。你誤解了符號中<-構造的含義。 result <- f handle並不意味着「將f handle的值賦值爲result」;它的意思是「將result綁定爲從」一元值f handle「(其中'提取'以您正在使用的特定Monad實例定義的某種方式(在本例中爲IO monad)'提取出來的值')。

即,對於一些類型類單子m,則<-語句採用在右手側和m a類型的表達式a類型的上左側的變量,並且所述可變結合的值。因此,在您的特定示例中,使用result <- f handle,我們有類型f result :: IO a,result :: areturn result :: IO a

PS做的,符號也有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

+1

酷!我把'<-'稱爲吸吮操作符,因爲它將rhs的值剔除:-) – drozzy 2011-12-20 01:11:14