Re: base package

2013-02-20 Thread Joachim Breitner
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

2013-02-20 Thread Joachim Breitner
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?)

2013-02-20 Thread Ian Lynagh
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