Input/Output in SML
Table of Contents
1. Introduction/Overview
I'm curious about the implementation details of input/output in Haskell and Standard ML, specifically how they compare to each other.
The Standard ML input/output seems to be specified in the Standard Basis library.
1.1. Observation
There seems to be no adequate way to formally specify input/output. Consequently, this is the only source of impurity which does not appear in the formal definition of Standard ML.
Perhaps I am wildly optimistic and/or ignorant here. For example, there may be some impurity in concurrent programming that I am unaware of…
I also do not believe there is any adequate way to reason about IO. The naive solution is to treat Standard ML's streams like a stack of strings (possibly with metadata like timestamps). But this is inadequate for concurrent systems.
2. Haskell
Haskell's IO Monad works with an abstraction called "handles". They are defined as (stripping back to bare bones):
data Handle
= FileHandle FilePath !(MVar Handle__)
| DuplexHandle FilePath !(MVar Handle__) !(MVar Handle__)
data Handle__ = Handle__ {
haFD :: !FD
haType :: HandleType
haIsBin :: Bool
haIsStream :: Bool
haBufferMode :: BufferMode
haBuffer :: !(IORef Buffer)
haBuffers :: !(IORef BufferList)
haOtherSide :: (Maybe (MVar Handle__))
}
Then openFile :: FilePath -> IOMode -> IO Handle creates a new IO
monad wrapping around any IO computations involving the given file.
Roughly, a Handle is approximately equivalent to a union of a Reader
and Writer in Standard ML. Instead of file descriptors, Standard ML
uses OS.IO.iodesc for a platform-independent way to describe "files".
Then Haskell's IO roughly corresponds to the TextIO module in Standard
ML, but in a monadic fashion.