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
>