IO Semantics
From HaskellWiki
(Difference between revisions)
m |
m |
||
| Line 25: | Line 25: | ||
If a <hask>PutChar</hask> node is encountered, the character data contained at that node is output to the terminal and then its subtree is executed. It is only at this point that Haskell code is ever necessarily evaluated in order to determine what character should be displayed before continuing. If a <hask>GetChar</hask> node is encountered, a character is read from the terminal (blocking if necessary) and the subtree corresponding to the character received is executed. If <hask>Done</hask> is encountered the program ends. | If a <hask>PutChar</hask> node is encountered, the character data contained at that node is output to the terminal and then its subtree is executed. It is only at this point that Haskell code is ever necessarily evaluated in order to determine what character should be displayed before continuing. If a <hask>GetChar</hask> node is encountered, a character is read from the terminal (blocking if necessary) and the subtree corresponding to the character received is executed. If <hask>Done</hask> is encountered the program ends. | ||
| - | The primitive IO commands are defined using these constructors | + | The primitive IO commands are defined using these constructors. |
<haskell> | <haskell> | ||
putChar :: Char -> IO () | putChar :: Char -> IO () | ||
| Line 33: | Line 33: | ||
getChar = IO (\k -> GetChar (\x -> k x)) | getChar = IO (\k -> GetChar (\x -> k x)) | ||
</haskell> | </haskell> | ||
| + | |||
| + | If the <hask>PutChar</hask> constructor was defined (isomorphically) as | ||
| + | <haskell> | ||
| + | | PutChar Char (() -> IOTree) | ||
| + | </haskell> | ||
| + | |||
| + | Then the primitive IO commands could be defined directly in terms of these constructors: | ||
| + | |||
| + | <haskell> | ||
| + | putChar :: Char -> IO () | ||
| + | putChar = IO . PutChar | ||
| + | |||
| + | getChar :: IO Char | ||
| + | getChar = IO GetChar | ||
| + | </haskell> | ||
| + | |||
| + | |||
Other teletype commands can be defined in terms of these primitives | Other teletype commands can be defined in terms of these primitives | ||
<haskell> | <haskell> | ||
Revision as of 14:47, 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))
PutChar
| PutChar Char (() -> IOTree)
Then the primitive IO commands could be defined directly in terms of these constructors:
putChar :: Char -> IO () putChar = IO . PutChar getChar :: IO Char getChar = IO GetChar
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
