Exposing newtype coercions to Haskell

Joachim Breitner mail at joachim-breitner.de
Mon Jul 1 13:59:48 CEST 2013


this is related to
I tried to hack up a little prototype of this, and this “works” now:

        import GHC.NT
        newtype Age = Age Int deriving Show
        ageNT :: NT Age Int
        ageNT = createNT
        newtype MyList a = MyList [a] deriving Show
        myListNT :: NT (MyList a) [a]
        myListNT = createNT
        main = do
            let n = 1 :: Int
            let a = coerce (sym ageNT) 1
            let l1 = [a]
            let l2 = coerce (listNT ageNT) l1
            let l3 = coerce (sym myListNT) l2
            print a
            print l2
            print l3
will print

        Age 1
        MyList [1]

and no unsafeCoerce and no map is used in the production of this output.

The GHC.NT module provides:

data NT a b
coerce :: NT a b -> a -> b
refl   :: NT a a
sym    :: NT a b -> NT b a
trans  :: NT a b -> NT b c -> NT a c
createNT :: NT a b
listNT :: NT a b -> NT [a] [b]

where createNT takes the place of the "deriving foo :: NT a b" syntax:
At compile time, it is checked if its first type argument is a newtype
of the second, and the corresponding coercion is inserted, otherwise an
error is (well, will be) printed.

The idea is that these coercions will be guaranteed to be free (or
almost free; I am not sure if the coercion witness (NT a b) will
actually be optimized away).

The prototype can be found at
and is implemented as a GHC plugin compatible with GHC 7.6.3 (I chose
this route as it means not having to compile GHC). You can check if it
works for you via
$ ghc  -dcore-lint -package ghc --make test.hs  && ./test

The code itself is, well, at most prototype code quality and contains
quite a number of hacks and other warts, mostly due to my inexperience
with GHC hacking, and I could make use of some advice. Some more
concrete questions:

 * How do I look up a module (here GHC.NT.Type) and a name therein (NT)
in CoreM? I tried to go via getOrigNameCache, but passing the ModuleName
name to lookupModuleEnv yielded Nothing, although it seems to me to be
precisely the same name that I find in moduleEnvKeys. If I take the
ModuleName from that list, it works. Similar problems with the OccEnv.
Please see
for what I tried (and how I worked around it). This work-around also
prevents building the package with cabal right now.

 * I did not find generic Core traversal functions like 
traverse :: (Monad m) => (Expr a -> m (Maybe (Expr a))) -> Expr a -> m (Expr a)
which  I defined in
Are such traversals re-implemented everywhere or did I just not search
well enough?

 * On the core level, once I have a TyCon, I also have all DataCons
available. Is there already code present that checks if the currently
compiled module really should see the data constructors, i.e. if they
are exported? I see code in normaliseFfiType, but that seems to be
integrated in the type checker, and it seems I need a GlobalRdrEnv; can
I get such a thing in a Core2Core pass?


Joachim “nomeata” Breitner
  mail at joachim-breitner.dehttp://www.joachim-breitner.de/
  Jabber: nomeata at joachim-breitner.de  • GPG-Key: 0x4743206C
  Debian Developer: nomeata at debian.org
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: This is a digitally signed message part
URL: <http://www.haskell.org/pipermail/glasgow-haskell-users/attachments/20130701/5f2b5987/attachment.pgp>

More information about the Glasgow-haskell-users mailing list