I Hate IO

Ashley Yakeley ashley@semantic.org
Thu, 9 Aug 2001 21:10:01 -0700


At 2001-08-09 03:01, Simon Marlow wrote:

>I considered providing a different API for bidirectional streams, or
>perhaps requiring that bidirectional streams use separate Handles for
>read and write, but came to the conclusion that the user really doesn't
>care whether under the hood a single Handle is using separate buffers
>for read and write or just a single buffer, how much locking is going on
>or whatever.  The fact that these things are awkward to implement
>shouldn't show through in the library interface.
>
>It's definitely more convenient from the programmer's point of view to
>be able to use the *same* handle object for both read and write,
>otherwise you have to explain to people why they can have a read/write
>file handle but not a read/write handle for a TCP socket.

Well, how about something like this:


--
type TCPPortNumber = Word16
type IPAddress = Word32
data TCPPort = MkTCPPort IPAddress TCPPortNumber
data TCPSocket = ...

openTCP :: TCPPort -> IO TCPSocket
closeTCP :: TCPSocket -> IO ()
listenTCP :: TCPPortNumber -> (TCPConnection -> IO ()) -> IO ()
-- not sure about listenTCP

getRemoteAddressTCP :: TCPSocket -> IO TCPPort
getLocalAddressTCP :: TCPSocket -> IO TCPPort

receiveTCP :: TCPSocket -> Integer -> Integer -> IO (Maybe [Word8])
-- "receiveTCP socket waittime arraylength"
-- return "Nothing" if received end with no octets pending
-- return "Just array" where array is as many octets up to length as 
received by waittime
-- set waittime to 0 to not wait but return only available bytes in 
buffer.

receiveWaitForeverTCP :: TCPSocket -> Integer -> IO (Maybe [Word8])
-- Same, with infinite wait-time.
-- only useful if it can be interrupted by another thread

sendDataTCP :: TCPSocket -> [Word8] -> IO ()
sendEndTCP ::  TCPSocket -> IO ()
--

OK, this is just off-the-cuff and probably has many flaws, and I offer it 
merely for discussion, not as a proposal. It does, however, represent the 
kind of basic functionality I'd look for, or abstract, if writing a TCP 
application.

If programmers want to abstract away the differences between different 
types of network connections, well, this is Haskell so they can always 
write classes like this:

--
class (Monad m) => Closable s m | s -> m where
     close :: s -> m ()

class (Monad m) => Source s m d | s -> m d where
     read :: s -> Integer -> Integer -> m (Maybe [d])
     readWaitForever :: s -> Integer -> m (Maybe [d])

class (Monad m) => Sink s m d | s -> m d where
     writeData :: s -> [d] -> m ()
     writeEnd ::  s -> m ()

write s Nothing = writeEnd s
write s (Just d) = writeData s d

-- etc.


-- 
Ashley Yakeley, Seattle WA