10
Example: a memory-mapped Handle Random-access read/write doesn’t perform very well with ordinary buffered I/O. – Let’s implement a Handle backed by a memory- mapped file – We need to 1.define our device type 2.make it an instance of IODevice and BufferedIO 3.provide a way to create instances

11
Example: memory-mapped files 1.Define our device type data MemoryMappedFile = MemoryMappedFile { mmap_fd :: FD, mmap_addr :: !(Ptr Word8), mmap_length :: !Int, mmap_ptr :: !(IORef Int) } deriving Typeable Ordinary file descriptor, provided by GHC.IO.FD Address in memory where our file is mapped, and its length The current file pointer (Handles have a built-in notion of the “current position” that we have to emulate) Typeable is one of the requirements for making a Handle

19
More examples A Handle that pipes output bytes to a Chan Handles backed by Win32 HANDLEs Handle that reads from a Bytestring/text Handle that reads from text

20
The -1 mile view Inside the IO library – The file-descriptor functionality is cleanly separated from the implementation of Handles: GHC.IO.FD implements file descriptors, with instances of IODevice and BufferedIO GHC.IO.Handle.FD defines openFile, using FDs as the underlying device GHC.IO.Handle has nothing to do with FDs

22
Where to go from here This is a step in the right direction, but there is still some obvious ugliness – We haven’t changed the external API, only added to it – There should be a binary I/O layer hPutBuf working on Handles is wrong: binary Handles should have a different type in a sense, BufferedIO is a binary I/O layer: it is efficient, but inconvenient – FilePath should be an abstract type. On Windows, FilePath = String, but on Unix, FilePath = [Word8]. – Should we rethink Handles entirely? OO-style layers: binary IO, buffering, encoding Separate read Handles from write Handles? – read/write Handles are a pain