Imperative Object Destruction
Chris Angus
CAngus@Armature.com
Mon, 13 Nov 2000 09:27:07 -0000
why not create an abstract datatype
OpenFile a which is a monad
data OpenFile a = OpenFile (Maybe FileHandle -> IO a)
and create you operations in terms of this
openFile :: String -> OpenFile ()
count :: OpenFile Int
read :: Int -> OpenFile [Byte]
then you could habe a run function
runOF :: OpenFile a -> IO a
which ran whatever you wanted for the file and ensured tahthe file was
closed correctly afterwards.
How we would do this with 2 files however I'm not so sure.
> -----Original Message-----
> From: Ashley Yakeley [mailto:ashley@semantic.org]
> Sent: 13 November 2000 07:21
> To: Haskell List
> Subject: Imperative Object Destruction
>
>
> C++ provides a convenient mechanism for cleaning up stuff, the
> destructor, which is guaranteed to get called when an object
> passes out
> of scope (or something).
>
> I'm wondering how to make a Haskell equivalent for imperative
> code. For
> instance, consider a simple file API, with these operations:
>
> open: given a string (the filename), open an existing file
> with that
> name, return a file-handle (or fail)
>
> count: given a file-handle, get the length of the file
>
> read: given a file-handle, offset into the file and a
> number of bytes,
> read the file returning a list of bytes (or fail)
>
> write: given a file-handle, offset into the file and a list
> of bytes,
> write the bytes to the file at the offset
>
> close: given a file-handle, close the handle
>
> In C++ I could simply create an OpenFile class, with the
> close operation
> in the destructor. The actual operations would be hidden from
> OpenFile's
> clients.
>
> I'd like to represent this API in Haskell so that the type-rules
> guarantee that in any imperative action of type 'IO a',
>
> 1. every opened file gets closed exactly once
>
> 2. no read or write operations are performed on file-handles
> that have
> not yet been opened, or that have already been closed.
>
> My first guess was to create a function that encapsulated the entire
> life-cycle of the file, passing in a function that would represent
> whatever one wished to do on the file:
>
> count :: Handle -> IO Integer
> read :: (Integer,Integer) -> Handle -> IO [Byte]
> write :: (Integer,[Byte]) -> Handle -> IO ()
> withFile :: (Handle -> IO a) -> String -> IO a
>
> 'withFile operation name' would open the file called 'name',
> perform the
> operation 'operation', and then close the file. So for
> instance, to get
> the length of a file named "/home/ashley/foo":
>
> withFile count "/home/ashley/foo"
>
> Trouble is, one can easily pass a return function to withFile to get
> ahold of the handle after it's been closed.
>
> My second guess was to use a special type to represent an imperative
> operation that needed a handle:
>
> read :: (Integer,Integer) -> HandleOperation [Byte]
> write :: (Integer,[Byte]) -> HandleOperation ()
> withFile :: HandleOperation a -> String -> IO a
>
> Of course, I'd then need to provide functions to compose/concatenate
> HandleOperation values. But I can't help thinking this
> problem is already
> well-known and there's a straightforward solution...
>
> --
> Ashley Yakeley, Seattle WA
>
>
> _______________________________________________
> Haskell mailing list
> Haskell@haskell.org
> http://www.haskell.org/mailman/listinfo/haskell
>