Haskell: actual IO monad implementation, in different language?

Viewed 5425

How is IO monad actually implemented?in sense of, what would be the actual implementation of the main function?

How would I call haskell function (IO) from another language and do I in that case need to maintain IO my self?

Does main pulls IO actions (Lazily) as references and then call them? Or it is interpreter job, when it found actions in its way it can call them? Or maybe something else?

Is there good IO monad implementation in different language which can help to deeply understand what happening in main function?

Edit:

Such hGetContents confuses me a lot, and makes me unsure how IO is really implemented.

Ok, let's say I have very simple pure Haskell interpreter witch unfortunately has no IO support and for curiosity I want to add this IO actions to it (unsafeIO tricks also). It is hard to get it from GHC, Hugs or others.

8 Answers

Note: my experience with Clean is minimal - consider yourself warned!

Based on System.IO, using a variation of an approach described by F. Warren Burton:

  • definition module System.Alt.IO
    
    from Control.Applicative import class pure, class <*>, class Applicative
    from Data.Functor import class Functor
    from Control.Monad import class Monad
    from StdOverloaded import class toString
    from System._OI import OI
    
    :: IO a = IO .(*OI -> a)
    
    execIO :: !(IO a) !*World -> *World
    
    evalIO :: !(IO a) !*World -> *(a, !*World)
    
    withOI :: (*OI -> .a) -> IO .a
    
    putStr :: String -> IO ()
    
    putStrLn :: String -> IO ()
    
    print :: a -> IO () | toString a
    
    getChar :: IO Char
    
    getLine :: IO String
    
    readFileM :: !String -> IO String
    
    writeFileM :: !String !String -> IO ()
    
    instance Functor IO
    instance pure IO
    instance <*> IO
    instance Monad IO
    
    unsafePerformIO :: !(*OI -> .a) -> .a
    unsafePerformIOTrue :: !(*OI -> a) -> Bool
    
  • implementation module System.Alt.IO
    
    import StdFile
    from StdFunc import o, id
    import StdMisc
    import StdString
    
    import System._OI
    import Control.Applicative
    import Control.Monad
    import Data.Functor
    from Text import class Text (trim), instance Text String
    
    execIO :: !(IO a) !*World -> *World
    execIO (IO g) world
      #  (u, world) = newOI world
      #! x = g u
      =  world
    
    evalIO :: !(IO a) !*World -> *(a, !*World)
    evalIO (IO g) world
      #  (u, world) = newOI world
      #! x = g u
      =  (x, world)
    
    withWorld :: (*World -> *(.a, *World)) -> IO .a
    withWorld f = IO g
    where
        g u
          # (x, world) = f (getWorld u)
          = from_world "withWorld" x world
    
    instance Functor IO
    where
        fmap f x = x >>= (lift o f)
    
    instance pure IO
    where
        pure x     = IO (\u -> case partOI u of (_, _) = x)
    
    instance <*> IO
    where
        (<*>) f g  = liftA2 id f g
    
    instance Monad IO where
      bind ma a2mb = IO (run ma)
        where
        run (IO g) u
          #  (u1, u2) = partOI u
          #! x        = g u1
          #  (IO k)   = a2mb x
          = k u2
    
    putStr :: String -> IO ()
    putStr str = withWorld f
      where
      f world
        # (out, world) = stdio world
        # out          = fwrites str out
        # (_, world)   = fclose out world
        = ((), world)
    
    putStrLn :: String -> IO ()
    putStrLn str = putStr (str +++ "\n")
    
    print :: a -> IO () | toString a
    print x = putStrLn (toString x)
    
    getChar :: IO Char
    getChar = withWorld f
      where
      f world
        # (input, world) = stdio world
        # (ok, c, input) = freadc input
        # (_, world)     = fclose input world
        = (c, world)
    
    getLine :: IO String
    getLine = withWorld f
      where
      f world
        # (input, world) = stdio world
        # (str, input)   = freadline input
        # (_, world)     = fclose input world
        = (trim str, world)
    
    readFileM :: !String -> IO String
    readFileM name = withWorld f
      where
      f world
        # (ok, file, world) = fopen name FReadText world
        # (str, file)       = freads file 16777216
        # (ok, world)       = fclose file world
        = (str, world)
    
    writeFileM :: !String !String -> IO ()
    writeFileM name txt = withWorld f
      where
      f world
        # (ok, file, world) = fopen name FWriteText world
        # file              = fwrites txt file
        # (ok, world)       = fclose file world
        = ((), world)
    
    unsafePerformIO :: !(*OI -> .a) -> .a
    unsafePerformIO f
      #! x = f make_oi
      =  x
    
    unsafePerformIOTrue :: !(*OI -> a) -> Bool
    unsafePerformIOTrue f
      #! x = f make_oi
      =  True
    
    make_oi
      # (u, w) = newOI make_world
      = from_world "make_oi" u w
    
    from_world :: String a !*World -> a
    from_world name x world
      | world_to_true world = x
      | otherwise           = abort ("error in +++ name +++ "\n") 
    
    world_to_true :: !*World -> Bool
    world_to_true world
      = code inline {
        pop_a 1
        pushB TRUE
    }
    
    make_world
      = code {
        fillI 65536 0
      }
    
  • definition module System._OI
    
    from StdFunc import id
    
    :: OI
    partOI :: *OI -> *(*OI, *OI)
    
    newOI :: *World -> *(*OI, *World)
    getWorld :: *OI -> *World
    
  • implementation module System._OI
    
    :: OI = OI
    
    partOI :: !*OI -> *(*OI, *OI)           // NOTE - this may need
    partOI u                                // to be defined with
      # u1 = OI                             // ABC instructions
      # u2 = id OI
      = (u1, u2)
    
    newOI :: !*World -> *(*OI, *World)      // ...or:  Start :: *OI -> ()
    newOI world
      = (OI, world)
    
    getWorld :: !*OI -> *World              // only needed because I/O
    getWorld OI                             // operations in Clean 3.0
      = code inline { fillA 65536 0 }       // rely on World values
    
Related