Re: base package
Hi, Am Freitag, den 15.02.2013, 23:00 +0100 schrieb Joachim Breitner: Am Freitag, den 15.02.2013, 14:50 + schrieb Simon Marlow: On 15/02/13 12:22, Joachim Breitner wrote: more progress: On top of base-pure, I created base-io involving GHC/IO and everything required to build it (which pulled in ST, some of Foreign and unfortunately some stuff related to Handles and Devices, because it is mentioned in IOException). This is the list of modules: You have a random collection of modules here :) I think you want to have the IO *monad* (GHC.IO) live in a lower layer, separate from the IO *library* (GHC.IO.Device and so on). Every Haskell implementation will need the IO monad, but they might want to replace the IO library with something else. Things like GHC.IORef, GHC.MVar can all live in a low-down layer because they're just wrappers over the primops. Right, that is my aim, and I started with GHC.IO. But unfortunately, the IO monad calls failIO, which is an IOError which has a field of type ioe_handle :: Maybe Handle (and one of type CInt) which pulls in all the rest there, and so far I did not have a good idea how to untangle that. What would break if fail would not raise an IOError, but a separate exception type, e.g. IOFailError? Probably too much, as users expect to catch the exception raised by fail with an exception handler that matches IOError. I’m still stuck at the problem of separating the definition of IO and Monad IO from all file related stuff, which is prevented by the Maybe Handle field in the IOError data type. Given that IOError is abstract to the „regular“ user (i.e. not to base-io-file), I guess we can afford to be a little bit hacky here. Two ideas come to my mind: 1. Instead of declaring the field as Maybe Handle, we define a pseudo-handle datatype data NotYetAHandle = NotYetAHandle and use Maybe NotYetAHandle in IOError, with the documented convention that only code in base-io-file (and code further down the tree) may use this field, and only after unsafeCoerce’ing it to a Maybe Handle. This way, the base-io package does not have to include the definition, but the IOError data type still has place for it. If the NotYetAHandle constructor is not exported, and base-io-file defines functions NotYetAHandle - Handle and Handle - NotYetAHandle via unsafeCoerce, then the unsafeness is very local and nobody can break the code without also using unsafeCoerce. 2. A little safer (and with a little more overhead) wold be to include Data.Dynamic in base and change the field to a Maybe Dynamic. Same procedure as above, only that a violation of the convention might be caught without crashes. Is having a package that provides io without providing file-related definition worth this kludge? Greetings, Joachimh -- Joachim nomeata Breitner Debian Developer nome...@debian.org | ICQ# 74513189 | GPG-Keyid: 4743206C JID: nome...@joachim-breitner.de | http://people.debian.org/~nomeata signature.asc Description: This is a digitally signed message part ___ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: base package
Hi, Am Mittwoch, den 20.02.2013, 14:57 +0100 schrieb Joachim Breitner: I’m still stuck at the problem of separating the definition of IO and Monad IO from all file related stuff, which is prevented by the Maybe Handle field in the IOError data type. re-reading „An Extensible Dynamically-Typed Hierarchy of Exceptions“ helped me to come up with this somewhat neat solution: The Monad IO instance uses an exception different from IOError: $ git show HEAD | filterdiff -i \*.cabal -i \*Fail\* -i \*/GHC/IO.hs --- a/GHC/IO.hs +++ b/GHC/IO.hs @@ -46,8 +46,7 @@ import GHC.ST import GHC.Exception import GHC.Show import Data.Maybe - -import {-# SOURCE #-} GHC.IO.Exception ( userError ) +import GHC.IO.Fail -- --- -- The IO Monad @@ -79,7 +78,7 @@ liftIO :: IO a - State# RealWorld - STret RealWorld a liftIO (IO m) = \s - case m s of (# s', r #) - STret s' r failIO :: String - IO a -failIO s = IO (raiseIO# (toException (userError s))) +failIO s = IO (raiseIO# (toException (IOFail s))) -- --- -- Coercions between IO and ST --- /dev/null +++ b/GHC/IO/Fail.hs @@ -0,0 +1,20 @@ +{-# LANGUAGE NoImplicitPrelude #-} +module GHC.IO.Fail where + +import GHC.Base +import GHC.Exception +import Data.Typeable +import GHC.Show + + +-- | This exception is thrown by the 'fail' method of the 'Monad' 'IO' instance. +-- +-- The Exception instance of IOException will also catch this, converting the +-- IOFail to a UserError, for compatibility and consistency with the Haskell +-- report +data IOFail = IOFail String + +instance Typeable IOFail -- deriving does not work without package +instance Show IOFail -- name changes to GHC +instance Exception IOFail + After this change, exposed-modules: GHC.IO.Fail, GHC.IO, GHC.IORef, GHC.ST, GHC.STRef is possible (and of course ST can be moved away as well). So far so good, but this breaks user code. So the solution is to make sure that to everyone who tries to catch an IOException (which will likely be part of some base-io-file), an IOFail will look like a IOError of type UserError: $ git show HEAD|filterdiff -i \*Exception.hs --- a/GHC/IO/Exception.hs +++ b/GHC/IO/Exception.hs @@ -45,9 +45,10 @@ import GHC.Show import GHC.Exception import Data.Maybe import GHC.IO.Handle.Types +import GHC.IO.Fail import Foreign.C.Types -import Data.Typeable ( Typeable ) +import Data.Typeable ( Typeable, cast ) -- -- Exception datatypes and operations @@ -222,7 +223,11 @@ data IOException } instance Typeable IOException -instance Exception IOException +instance Exception IOException where +toException = SomeException +fromException e = case cast e of +Just (IOFail s) - Just (userError s) +Nothing - cast e instance Eq IOException where (IOError h1 e1 loc1 str1 en1 fn1) == (IOError h2 e2 loc2 str2 en2 fn2) = Neat, isn’t it? Now I can proceed separating some of the Foreign stuff from the IO stuff. Greetings, Joachim -- Joachim nomeata Breitner Debian Developer nome...@debian.org | ICQ# 74513189 | GPG-Keyid: 4743206C JID: nome...@joachim-breitner.de | http://people.debian.org/~nomeata signature.asc Description: This is a digitally signed message part ___ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: base package (Was: GHC 7.8 release?)
On Fri, Feb 15, 2013 at 02:45:19PM +, Simon Marlow wrote: Remember that fingerprinting is not hashing. For fingerprinting we need to have a realistic expectation of no collisions. I don't think FNV is suitable. I'm sure it would be possible to replace the C md5 code with some Haskell. Performance *is* important here though - Typeable is in the inner loop of certain generic programming libraries, like SYB. We currently just compare hash(str) for equality, right? Could we instead compare (hash str, str) ? That would be even more correct, even if a bad/cheap hash function is used, and would only be slower for the case where the types match (unless you're unlucky and get a hash collision). In fact, we may be able to arrange it so that in the equal case the strings are normally exactly the same string, so we can do a cheap pointer equality test (like ByteString already does) to make the equal case fast too (falling back to actually checking the strings are equal, if they aren't the same string). Thanks Ian ___ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users