Re: Imperative Object Destruction
On Mon, 13 Nov 2000, Ashley Yakeley wrote: > Well, it doesn't solve the problem I'm interested in. The file-handling > is just an example, I'd like to solve it for any kind of object > destruction, so that this kind of error is always caught at compile-time. I don't think it's possible without limiting convenience / usefulness. When an arbitrary IO action may be executed to deal with the object, it can put it into a mutable reference and then used anywhere, or passed to another thread, and you've lost control over it. It can be done in a way similar to the ST monad of GHC and Hugs: tagging objects and actions with type variables and using a special type for running the computation which ensures that reference don't escape the computation (and if they are accessed from elsewhere then they are not usable there anyway). It restricts doable actions to those provided by the ST monad - no mixing with arbitrary IO. -- Marcin 'Qrczak' Kowalczyk ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
RE: Imperative Object Destruction
> >That's the problem. And I think your solution is overly complicated. > > > >Why not copy what Common Lisp does, just that Haskell can do > it without > >macros: > > > >withOpenFile :: FilePath -> IOMode -> (Handle -> IO a) -> IO a > >withOpenFile name mode action = do > >handle <- openFile name mode > >result <- (action handle) `finally` (hClose handle) > >return result > > > >Usage: > > > >count :: Handle -> IO Int > >read :: Handle -> IO [Byte] > > > >fileLength <- withOpenFile "filename" ReadMode $ \handle -> > > count handle > >fileContent <- withOpenFile "filename" ReadMode $ \handle -> > > read handle > > Doesn't fulfill condition 2: > > 2. no read or write operations are performed on file-handles > that have > not yet been opened, or that have already been closed. > > ...since you can do > > stealHandle = withOpenFile "filename" ReadMode (\handle -> handle) > stealHandle >>= read If you want to enforce this kind of encapsulation using the type system, you could try using the runST trick, something like: withOpenFile :: FilePath -> IOMode -> (forall s . OpenFile s -> IO a) -> IO a of course, this needs the universal quantification extensions implemented in Hugs & GHC. Cheers, Simon ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Re: Imperative Object Destruction
At 2000-11-13 02:39, Hannah Schroeter wrote: >And that yields an exception, as the handle is definitely closed. > >Is there any *real* problem with this? Well, it doesn't solve the problem I'm interested in. The file-handling is just an example, I'd like to solve it for any kind of object destruction, so that this kind of error is always caught at compile-time. -- Ashley Yakeley, Seattle WA ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Re: Imperative Object Destruction
At 2000-11-13 02:30, Ashley Yakeley wrote: > stealHandle = withOpenFile "filename" ReadMode (\handle -> handle) > stealHandle >>= read Sorry, that should read stealHandle = withOpenFile "filename" ReadMode return stealHandle >>= read -- Ashley Yakeley, Seattle WA ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Re: Imperative Object Destruction
Hello! On Mon, Nov 13, 2000 at 02:30:17AM -0800, Ashley Yakeley wrote: > [...] > Doesn't fulfill condition 2: > 2. no read or write operations are performed on file-handles that have > not yet been opened, or that have already been closed. > ...since you can do > stealHandle = withOpenFile "filename" ReadMode (\handle -> handle) > stealHandle >>= read And that yields an exception, as the handle is definitely closed. Is there any *real* problem with this? Kind regards, Hannah. ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
RE: Imperative Object Destruction
At 2000-11-13 01:27, Chris Angus wrote: >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. This is a slight generalisation of my scheme, from which withFile :: OpenFile a -> String -> IO a withFile operation name = runOF (openFile name >> operation) >How we would do this with 2 files however I'm not so sure. Looks like you can't. This might work, however: read :: (Int,Int) -> OpenFile IO [Byte] write :: (Int,[Byte]) -> OpenFile IO () withFile :: OpenFile a -> String -> a copyFile :: OpenFile OpenFile IO () withFile (withFile copyFile "dest") "source" ...but I'm not sure how to write copyFile. -- Ashley Yakeley, Seattle WA ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Re: Imperative Object Destruction
At 2000-11-13 02:18, Hannah Schroeter wrote: >That's the problem. And I think your solution is overly complicated. > >Why not copy what Common Lisp does, just that Haskell can do it without >macros: > >withOpenFile :: FilePath -> IOMode -> (Handle -> IO a) -> IO a >withOpenFile name mode action = do >handle <- openFile name mode >result <- (action handle) `finally` (hClose handle) >return result > >Usage: > >count :: Handle -> IO Int >read :: Handle -> IO [Byte] > >fileLength <- withOpenFile "filename" ReadMode $ \handle -> > count handle >fileContent <- withOpenFile "filename" ReadMode $ \handle -> > read handle Doesn't fulfill condition 2: 2. no read or write operations are performed on file-handles that have not yet been opened, or that have already been closed. ...since you can do stealHandle = withOpenFile "filename" ReadMode (\handle ->handle) stealHandle >>= read -- Ashley Yakeley, Seattle WA ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Re: Imperative Object Destruction
Hello! On Mon, Nov 13, 2000 at 09:27:07AM -, Chris Angus wrote: > 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. > [...] That's the problem. And I think your solution is overly complicated. Why not copy what Common Lisp does, just that Haskell can do it without macros: withOpenFile :: FilePath -> IOMode -> (Handle -> IO a) -> IO a withOpenFile name mode action = do handle <- openFile name mode result <- (action handle) `finally` (hClose handle) return result Usage: count :: Handle -> IO Int read :: Handle -> IO [Byte] fileLength <- withOpenFile "filename" ReadMode $ \handle -> count handle fileContent <- withOpenFile "filename" ReadMode $ \handle -> read handle or even, if you want both results without opening the file twice: rewind :: Handle -> IO () (fileLength, fileContent) <- withOpenFile "filename" ReadMode $ \handle -> do len <- count handle rewind handle cont <- read handle return (len, cont) Two files: result <- withOpenFile "file1" ReadMode $ \handle1 -> withOpenFile "file2" ReadMode $ \handle2 -> ... Kind regards, Hannah. ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
RE: Imperative Object Destruction
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:[EMAIL PROTECTED]] > 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 > [EMAIL PROTECTED] > http://www.haskell.org/mailman/listinfo/haskell > ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
RE: Imperative Object Destruction
At 2000-11-13 00:58, Simon Peyton-Jones wrote: >| 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). > >Haskell doesn't but GHC has an extension (finalisers) that does. >There's a discussion of the issues in our paper about weak pointers >and finalisers > http://research.microsoft.com/~simonpj/#weak I assume you mean finalisers for ordinary Haskell values after they're no longer referenced. That's actually a separate issue, I'm more interested in doing finalisation in Haskell's existing monadic imperative model, something that shouldn't need any runtime extensions. -- Ashley Yakeley, Seattle WA ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
RE: 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). Haskell doesn't but GHC has an extension (finalisers) that does. There's a discussion of the issues in our paper about weak pointers and finalisers http://research.microsoft.com/~simonpj/#weak Simon ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell