[英]How withFile is implemented in haskell
Following a haskell tutorial , the author provides the following implementation of the withFile method: 在haskell教程之后 ,作者提供了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
But why do we need to wrap the result
in a return
? 但为什么我们需要将
result
包装return
? Doesn't the supplied function f
already return an IO
as can be seen by it's type Handle -> IO a
? 提供的函数
f
是否已经返回IO
因为它的类型Handle -> IO a
?
You're right: f
already returns an IO
, so if the function were written like this: 你是对的:
f
已经返回一个IO
,所以如果函数是这样编写的:
withFile' path mode f = do
handle <- openFile path mode
f handle
there would be no need for a return. 没有必要返回。 The problem is
hClose handle
comes in between, so we have to store the result first: 问题是
hClose handle
介于两者之间,所以我们必须先存储结果:
result <- f handle
and doing <-
gets rid of the IO
. 并做
<-
摆脱IO
。 So return
puts it back. 所以
return
把它放回去。
This is one of the tricky little things that confused me when I first tried Haskell. 当我第一次尝试Haskell时,这是让我困惑的棘手小事之一。 You're misunderstanding the meaning of the
<-
construct in do-notation. 你误解了
<-
构造在do-notation中的含义。 result <- f handle
doesn't mean "assign the value of f handle
to result
"; result <- f handle
并不意味着“将f handle
的值赋给result
”; it means "bind result
to a value 'extracted' from the monadic value of f handle
" (where the 'extraction' happens in some way that's defined by the particular Monad instance that you're using, in this case the IO monad). 它意味着“将
result
绑定到从f handle
的monadic值中提取的值”(其中'extract'以某种方式发生,由您正在使用的特定Monad实例定义,在本例中为IO monad)。
Ie, for some Monad typeclass m, the <-
statement takes an expression of type ma
in the right hand side and a variable of type a
on the left hand side, and binds the variable to a value. 即,对于一些Monad类型类m,
<-
语句在右侧采用类型为ma
的表达式,在左侧采用类型a
的变量,并将该变量绑定到一个值。 Thus in your particular example, with result <- f handle
, we have the types f result :: IO a
, result :: a
and return result :: IO a
. 因此,在您的特定示例中,使用
result <- f handle
,我们有类型f result :: IO a
, result :: a
并return result :: IO a
。
PS do-notation has also a special form of let
(without the in
keyword in this case!) that works as a pure counterpart to <-
. PS do-notation还有一种特殊形式的
let
(在这种情况下没有in
关键字!),它作为<-
的纯粹对应物。 So you could rewrite your example as: 所以你可以将你的例子重写为:
withFile' :: FilePath -> IOMode -> (Handle -> IO a) -> IO a
withFile' path mode f = do
handle <- openFile path mode
let result = f handle
hClose handle
result
In this case, because the let
is a straightforward assignment, the type of result
is IO a
. 在这种情况下,因为
let
是一个简单的赋值, result
的类型是IO a
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.