# IO Semantics

### From HaskellWiki

(Difference between revisions)

m |
(rename unIO into runIO) |
||

Line 5: | Line 5: | ||

The idea to to define <hask>IO</hask> as | The idea to to define <hask>IO</hask> as | ||

<haskell> | <haskell> | ||

− | newtype IO a = IO { | + | newtype IO a = IO {runIO :: (a -> IOTree) -> IOTree} |

</haskell> | </haskell> | ||

This is equivalent to defining <hask>IO</hask> as <hask>Cont IOTree</hask> from the [[monad template library]]. The monad functions for <hask>IO</hask> are derived from the monad functions for <hask>Cont</hask>. | This is equivalent to defining <hask>IO</hask> as <hask>Cont IOTree</hask> from the [[monad template library]]. The monad functions for <hask>IO</hask> are derived from the monad functions for <hask>Cont</hask>. | ||

<haskell> | <haskell> | ||

return x = IO (\k -> k x) | return x = IO (\k -> k x) | ||

− | x >>= f = IO (\k -> | + | x >>= f = IO (\k -> runIO x (\a -> runIO (f a) (\b -> k b))) |

</haskell> | </haskell> | ||

<hask>IOTree</hask> is the ultimate result of a program. For simplicity we will give an example of <hask>IOTree</hask> that gives semantics for teletype IO. | <hask>IOTree</hask> is the ultimate result of a program. For simplicity we will give an example of <hask>IOTree</hask> that gives semantics for teletype IO. | ||

Line 45: | Line 45: | ||

We said that the ultimate result of a program is an <hask>IOTree</hask>, however the main function has type <hask>IO ()</hask>. This is isomorphic to <hask>(() -> IOTree) -> IOTree</hask>, or equivalently <hask>IOTree -> IOTree</hask> which is not right. | We said that the ultimate result of a program is an <hask>IOTree</hask>, however the main function has type <hask>IO ()</hask>. This is isomorphic to <hask>(() -> IOTree) -> IOTree</hask>, or equivalently <hask>IOTree -> IOTree</hask> which is not right. | ||

− | The simple solution to this is that the runtime system produces an <hask>IOTree</hask> from main by evaluating <hask> | + | The simple solution to this is that the runtime system produces an <hask>IOTree</hask> from main by evaluating <hask>runIO main (\() -> Done) :: IOTree</hask>. Here <hask>\() -> Done</hask> represents the "rest of the program", which in this case is nothing. |

The sophisticated solution to this problem is that <hask>main</hask> is passed to the operating system which will bind the next program (perhaps a shell) to <hask>main</hask>. Thus the semantics of our Haskell program becomes embedded into the semantics of the entire operating system run. | The sophisticated solution to this problem is that <hask>main</hask> is passed to the operating system which will bind the next program (perhaps a shell) to <hask>main</hask>. Thus the semantics of our Haskell program becomes embedded into the semantics of the entire operating system run. |

## Revision as of 10:02, 18 July 2008

## Semantics of IO: A Continuation Approach

The following is inspired by Luke Palmer's post. This only describes one possible semantics ofIO a

IO

newtype IO a = IO {runIO :: (a -> IOTree) -> IOTree}

IO

Cont IOTree

IO

Cont

return x = IO (\k -> k x) x >>= f = IO (\k -> runIO x (\a -> runIO (f a) (\b -> k b)))

IOTree

IOTree

data IOTree = Done | PutChar Char IOTree | GetChar (Char -> IOTree)

GetChar

IOTree

IOTree

PutChar

GetChar

Done

The primitive IO commands are defined using these constructors

putChar :: Char -> IO () putChar x = IO (\k -> PutChar x (k ())) getChar :: IO Char getChar = IO (\k -> GetChar (\x -> k x))

Other teletype commands can be defined in terms of these primitives

putStr :: String -> IO () putStr = mapM_ putChar

IOTree

IOTree

| SysCallName p1 p2 ... pn (r -> IOTree)

p1

pn

r

PutChar

GetChar

IOTree

IOTree

IO ()

(() -> IOTree) -> IOTree

IOTree -> IOTree

IOTree

runIO main (\() -> Done) :: IOTree

\() -> Done

main

main

IO a

IO (\k -> filterTree (not . isPutChar) k ()) :: IO ()

putChar