问题描述
这是我最后一个问题的后续。
解决这个问题的方法是删除一些monad,并允许执行IO操作。
为什么我需要让单子们安静?有没有一种方法来执行IO而不拆开?
注意:这是一个 what-if 多于这是一个关于好的或不好的做法的问题。 可能这会帮助你想到 IO
as type IO a = World - > (a,世界)
;也就是一个函数,它将当前计算机的状态作为其唯一参数,并返回一个新的状态以及一些值 a
。这与GHC内部的 IO
的实际执行没有太大的区别,所以希望我们可以原谅这种类比的交流方式。
所以 readFile :: FilePath - > IO字符串
,例如,变为 readFile :: FilePath - >世界 - > (a,World)
。
和 main :: IO()
main :: World - > ((),World)
。
然而,这意味着类型为 IO _
是惰性的。他们只是功能!函数在赋值之前不能做任何事情;在我们的例子中,函数需要的值是 World
对象,我们无法构建。这就是Haskell中IO的美妙之处:我们可以通过使用我们所熟悉并喜爱的monadic运算符(return,bind)来建立一个 IO
动作,但它只能在运行时传入 World
对象。
这意味着任何 IO
我们构建的行为不会穿过 main
不会被执行。
foobar :: [Char] - > IO [IO()]
,我们当然可以观察到返回值:
main :: IO ()
main = do
ios< - foobarstring
printgoodbye
但是,直到我们解构 ios
并绑定内部的 IO
这些操作值收到他们希望获得的 World
:
$ p $ main :: IO()
main = do
ios< - foobar
ios !! 0
ios !! 1
ios !! 2
...
printgoodbye
或者,
main = do
ios< - foobar
序列ios
printgoodbye
希望这有助于您。
This is a follow up of my last question.IO action nested in other monads not executing
The solution to that question was to remove some of the monads, and that allowed the IO action to execute.
Why did I need to unnest the monads? Is there a way to execute the IO without unnesting?
Note: This is a what-if more than it is a question about good or bad practice.
Perhaps it would help to think of IO
as type IO a = World -> (a, World)
; that is, a function that takes as its only parameter the current state of your computer and returns a new state along with some value a
. This is not too dissimilar from the actual implementation of IO
in GHC internals, so hopefully we can forgive the (abject) method of communicating by analogy here.
So readFile :: FilePath -> IO String
, for example, becomes readFile :: FilePath -> World -> (a, World)
.
And main :: IO ()
is really main :: World -> ((), World)
.
What this means, however, is that values with type IO _
are inert. They are just functions! Functions cannot do anything until they are given a value; in our case, the value the function wants is a World
object, which we have no way of constructing. Therein lies the beauty of IO in Haskell: we can build up an IO
action by using the monadic operators we know and love (return, bind) but it cannot do anything until the runtime passes in the World
object.
Which means that any IO
action we build that isn't threaded through main
won't be executed.
So, with foobar :: [Char] -> IO [IO ()]
, we can certainly observe the return value:
main :: IO ()
main = do
ios <- foobar "string"
print "goodbye"
But it's not until we deconstruct ios
and bind the internal IO
values that those actions receive the World
they desire:
main :: IO ()
main = do
ios <- foobar
ios !! 0
ios !! 1
ios !! 2
...
print "goodbye"
Or, for short,
main = do
ios <- foobar
sequence ios
print "goodbye"
Hope this helps.
这篇关于为什么嵌套在其他monad中的IO不能执行?有没有办法强制他们?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!