Why will a IO nested in other monads not execute? Is there a way to force them to?

前端 未结 3 957
迷失自我
迷失自我 2021-01-19 10:19

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 all

3条回答
  •  情话喂你
    2021-01-19 10:45

    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.

提交回复
热议问题