Wired-in type class

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

Wired-in type class

Joachim Breitner-2
Dear List,

I have some questions about the inner parts of GHC, where I need to
learn a lot. This is related to my attempts on newtype casting, but
should probably be kept separate from the conceptual discussions.

Say I need to create a wired-in type class, because it cannot be
represented in Haskell. The Core type constructor that will come out of
it will have one field of type ~R#, which is the reason why I cannot
write it in Haskell.

It seems that defining something wired-in is not a very local operation
that affects, at least primops.txt.pp and TysPrim.lhs. Does it affect
more?

It seems that there is not precedent of a wired-in type class. Is that
possible without touching too many parts of the compiler?

Or is it saner to just have "class NT a b" in a module in ghc-prim
without the constraint and use special magic when compiling that file to
add the required field to the data constructor representing the class?
(Similar to how the kind of ~ is adjusted during compilation?)

Greetings,
Joachim


--
Joachim ?nomeata? Breitner
  mail at joachim-breitner.de ? http://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/ghc-devs/attachments/20130816/4fdd9947/attachment.pgp>

Reply | Threaded
Open this post in threaded view
|

Wired-in type class

Iavor Diatchki
Hi Joachim,

Examples of classes with built-in features in GHC are `SingI`, used for
type-literals, and `IP`, used to implement implicit parameters.
I am not sure what is the best way to implement class NT (I am just back
from vacation, so I haven't had a chance to catch up on e-mails yet), but
here are some pointers that I've found useful while doing things like that:

First, you'll have to teach GHC about the new class.  As long as it works,
the simplest thing would be to declare the class somewhere in the base
library, and then add an entry for it in prelude/PrelNames.hs.  For
example, take a look at `singIClassName` (the actual class is declared in
GHC.TypeLits in the `base` library). It is important to add the class to
`basicKnownKeyNames`, so that GHC knows that it should use the name you
declared, rather than making up another name.

Once you have a name for the new class, you can add built-in instances for
it.  `SingI` provides a bunch of built-in instances, which is done in
`typecheck/TcInteract.hs`.  The actual instances are in function
`matchClassInst`, where we take a look at the name of the class and the its
type parameters, and if everything is as expected, then we create some
evidence (i.e., a kind of dictionary for it).  The exact shape of the
evidence depends on the class method, but `makeDict` in the same function
may give you an idea of what to do in your particular case.  If the
evidence needs to be more complex (i.e., you need to generate an
implementation in Core, Simon showed me another trick involving rules,
which is a bit of a hack, but does seem to work, so I could show you what I
did there too, so just ask).

Hope this helps,
-Iavor
















On Fri, Aug 16, 2013 at 6:43 AM, Joachim Breitner
<mail at joachim-breitner.de>wrote:

> Dear List,
>
> I have some questions about the inner parts of GHC, where I need to
> learn a lot. This is related to my attempts on newtype casting, but
> should probably be kept separate from the conceptual discussions.
>
> Say I need to create a wired-in type class, because it cannot be
> represented in Haskell. The Core type constructor that will come out of
> it will have one field of type ~R#, which is the reason why I cannot
> write it in Haskell.
>
> It seems that defining something wired-in is not a very local operation
> that affects, at least primops.txt.pp and TysPrim.lhs. Does it affect
> more?
>
> It seems that there is not precedent of a wired-in type class. Is that
> possible without touching too many parts of the compiler?
>
> Or is it saner to just have "class NT a b" in a module in ghc-prim
> without the constraint and use special magic when compiling that file to
> add the required field to the data constructor representing the class?
> (Similar to how the kind of ~ is adjusted during compilation?)
>
> Greetings,
> Joachim
>
>
> --
> Joachim ?nomeata? Breitner
>   mail at joachim-breitner.de ? http://www.joachim-breitner.de/
>   Jabber: nomeata at joachim-breitner.de  ? GPG-Key: 0x4743206C
>   Debian Developer: nomeata at debian.org
>
> _______________________________________________
> ghc-devs mailing list
> ghc-devs at haskell.org
> http://www.haskell.org/mailman/listinfo/ghc-devs
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/ghc-devs/attachments/20130816/61fe5f34/attachment.htm>

Reply | Threaded
Open this post in threaded view
|

Wired-in type class

Joachim Breitner-2
Hi,

thanks for your pointers, they are very helpful. The problem is that one
way of implementing NT involves a class declaration (not just instances)
that I cannot write in Haskell. I tried to completely generate the the
class in GHC.Prim, without corresponding source, but that failed (e.g.
that module has mi_decl = []; I took that as a sign that I?m not on the
right track).

So I am back at generating a TypeCon in GHC.Prim which (to Haskell
abstractly) contains the non-Haskell-fields and then have a simple class
with one member of that type. Semantically all the same, and easier
implementation.


Am Freitag, den 16.08.2013, 10:25 -0700 schrieb Iavor Diatchki:

> The exact shape of the evidence depends on the class method, but
> `makeDict` in the same function may give you an idea of what to do in
> your particular case.  If the evidence needs to be more complex (i.e.,
> you need to generate an implementation in Core, Simon showed me
> another trick involving rules, which is a bit of a hack, but does seem
> to work, so I could show you what I did there too, so just ask).

In my case, I?d like to generate instances when the users asks for it
via derving clauses; but there as well I have the issue that deriving
stuff happens before desugaring, but the implementation will have to be
in Core. So I?m very much interested in the trick.

Greetings,
Joachim

--
Joachim ?nomeata? Breitner
  mail at joachim-breitner.de ? http://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/ghc-devs/attachments/20130816/00822a39/attachment.pgp>

Reply | Threaded
Open this post in threaded view
|

Wired-in type class

Simon Peyton Jones
Joachim

I've been thinking about this a bit.  I think for you the best path may be this:

* Make NT a wired-in Class.  We don't have any of these at the moment, but there should be no difficulty in creating one, along the lines of the wired-in TyCons in TysWiredIn.  Its data con should have the type
        NT :: (a ~R# b) -> NT a b

* Also make ntCast a wired-in It (see example in MkId), with an unfolding like
        ntCast :: NT a b => a -> b
        ntCast = /\ab. \d:NT a b.  \x:a.
                       case d of
                         NT (g : a ~R# b) -> x |> g                      

* In the base module, define NT as a data type, and ntCast as a function:

        data NT a b where
           NT :: NT a a

        ntCast :: NT a b -> a -> b
        ntCast NT x = x

These definitions will never get imported, because the definitions are wired-in.
And indeed they are slightly wrong: we are declaring NT as a data type not
a class, and the type of NT will be
        NT :: (a ~T# b) -> NT a b

But they may still be used if, for example, we say (map ntCast xs).  
All that matters is that their execution behaviour is correct, which it will be.

* We are only going to allow GHC-derived instances of NT.  The instance for NT a a
may be super-special: as Iavor mentions we can check for that specially in matchInst.
All the others are generated by a 'deriving' clause.

Happy to discuss.  There is probably too much to do, and get settled, for it to be in 7.8 anyway.

Simon

|  -----Original Message-----
|  From: ghc-devs [mailto:ghc-devs-bounces at haskell.org] On Behalf Of Joachim
|  Breitner
|  Sent: 16 August 2013 20:54
|  To: ghc-devs
|  Subject: Re: Wired-in type class
|  
|  Hi,
|  
|  thanks for your pointers, they are very helpful. The problem is that one way of
|  implementing NT involves a class declaration (not just instances) that I cannot
|  write in Haskell. I tried to completely generate the the class in GHC.Prim, without
|  corresponding source, but that failed (e.g.
|  that module has mi_decl = []; I took that as a sign that I?m not on the right
|  track).
|  
|  So I am back at generating a TypeCon in GHC.Prim which (to Haskell
|  abstractly) contains the non-Haskell-fields and then have a simple class with one
|  member of that type. Semantically all the same, and easier implementation.
|  
|  
|  Am Freitag, den 16.08.2013, 10:25 -0700 schrieb Iavor Diatchki:
|  
|  > The exact shape of the evidence depends on the class method, but
|  > `makeDict` in the same function may give you an idea of what to do in
|  > your particular case.  If the evidence needs to be more complex (i.e.,
|  > you need to generate an implementation in Core, Simon showed me
|  > another trick involving rules, which is a bit of a hack, but does seem
|  > to work, so I could show you what I did there too, so just ask).
|  
|  In my case, I?d like to generate instances when the users asks for it via derving
|  clauses; but there as well I have the issue that deriving stuff happens before
|  desugaring, but the implementation will have to be in Core. So I?m very much
|  interested in the trick.
|  
|  Greetings,
|  Joachim
|  
|  --
|  Joachim ?nomeata? Breitner
|    mail at joachim-breitner.de ? http://www.joachim-breitner.de/
|    Jabber: nomeata at joachim-breitner.de  ? GPG-Key: 0x4743206C
|    Debian Developer: nomeata at debian.org

Reply | Threaded
Open this post in threaded view
|

Wired-in type class

Joachim Breitner-2
Hi,

Am Sonntag, den 18.08.2013, 15:24 +0000 schrieb Simon Peyton-Jones:
> * Make NT a wired-in Class.  We don't have any of these at the moment, but there should be no difficulty in creating one, along the lines of the wired-in TyCons in TysWiredIn.  Its data con should have the type
> NT :: (a ~R# b) -> NT a b
>
> * Also make ntCast a wired-in It (see example in MkId), with an unfolding like
> ntCast :: NT a b => a -> b
> ntCast = /\ab. \d:NT a b.  \x:a.
>                        case d of
>                          NT (g : a ~R# b) -> x |> g                      

thanks; the Core of ntCast looks very much like what I have at the
moment (although I still use an intermediate datatype; but that can
easily be changed later).

> * In the base module, define NT as a data type, and ntCast as a function:
>
> data NT a b where
>   NT :: NT a a
>
> ntCast :: NT a b -> a -> b
> ntCast NT x = x
>
> These definitions will never get imported, because the definitions are wired-in.
> And indeed they are slightly wrong: we are declaring NT as a data type not
> a class, and the type of NT will be
> NT :: (a ~T# b) -> NT a b
>
> But they may still be used if, for example, we say (map ntCast xs).  
> All that matters is that their execution behaviour is correct, which it will be.

Is there any reason to prefer such ?slightly wrong? definitions which
are overwritten with built-in stuff over simply putting the type
constructors and functions into GHC.Prim?

> * We are only going to allow GHC-derived instances of NT.

Just to be sure: Preventing manual instances is currently not possible
and such a feature would have to be added to GHC, right?

> The instance for NT a a
> may be super-special: as Iavor mentions we can check for that specially in matchInst.
> All the others are generated by a 'deriving' clause.

For some reason I?m still trying hard to make NT as un-special as
possible, including a regular "NT a a" instance. Let?s see how far I get
with that.

I hope to have some code that I can show soon.

> Happy to discuss.  There is probably too much to do, and get settled, for it to be in 7.8 anyway.

I have absolutely no rush for 7.8, so that is not an issue from my side.

Greetings,
Joachim
--
Joachim ?nomeata? Breitner
  mail at joachim-breitner.de ? http://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/ghc-devs/attachments/20130818/9011163b/attachment.pgp>

Reply | Threaded
Open this post in threaded view
|

Wired-in type class

Gabor Greif-2
On 8/18/13, Joachim Breitner <mail at joachim-breitner.de> wrote:

> Hi,
>
> Am Sonntag, den 18.08.2013, 15:24 +0000 schrieb Simon Peyton-Jones:
>> * Make NT a wired-in Class.  We don't have any of these at the moment, but
>> there should be no difficulty in creating one, along the lines of the
>> wired-in TyCons in TysWiredIn.  Its data con should have the type
>> NT :: (a ~R# b) -> NT a b
>>
>> * Also make ntCast a wired-in It (see example in MkId), with an unfolding
>> like
>> ntCast :: NT a b => a -> b
>> ntCast = /\ab. \d:NT a b.  \x:a.
>>                        case d of
>>                          NT (g : a ~R# b) -> x |> g
>
> thanks; the Core of ntCast looks very much like what I have at the
> moment (although I still use an intermediate datatype; but that can
> easily be changed later).
>
>> * In the base module, define NT as a data type, and ntCast as a function:
>>
>> data NT a b where
>>   NT :: NT a a
>>
>> ntCast :: NT a b -> a -> b
>> ntCast NT x = x
>>
>> These definitions will never get imported, because the definitions are
>> wired-in.
>> And indeed they are slightly wrong: we are declaring NT as a data type
>> not
>> a class, and the type of NT will be
>> NT :: (a ~T# b) -> NT a b
>>
>> But they may still be used if, for example, we say (map ntCast xs).
>> All that matters is that their execution behaviour is correct, which it
>> will be.
>
> Is there any reason to prefer such ?slightly wrong? definitions which
> are overwritten with built-in stuff over simply putting the type
> constructors and functions into GHC.Prim?
>
>> * We are only going to allow GHC-derived instances of NT.
>
> Just to be sure: Preventing manual instances is currently not possible
> and such a feature would have to be added to GHC, right?
>

There is also user-supplied Typeable instances which are ignored (with
a warning?).

In your case that would be an error.

Cheers,

    Gabor



Reply | Threaded
Open this post in threaded view
|

Wired-in type class

Joachim Breitner-2
Hi,

Am Sonntag, den 18.08.2013, 21:54 +0200 schrieb Gabor Greif:

> There is also user-supplied Typeable instances which are ignored (with
> a warning?).

at least no Typeabe-specific warning:

Prelude> newtype Age = Age Int
Prelude> instance Typeable Age
Prelude> :m + Data.Typeable
Prelude Data.Typeable> instance Typeable Age

<interactive>:5:10: Warning:
    No explicit method or default declaration for `typeOf'
    In the instance declaration for `Typeable Age'

It seems that GHC does prevent it in Safe mode, though:

       -- Check that if the module is compiled with -XSafe, there are no
       -- hand written instances of old Typeable as then unsafe casts could be
       -- performed. Derived instances are OK.
       ; when (safeLanguageOn dflags) $
             mapM_ (\x -> when (typInstCheck x)
                               (addErrAt (getSrcSpan $ iSpec x) typInstErr))
                   local_infos
(compiler/typecheck/TcInstDcls.lhs)

Greetings,
Joachim


--
Joachim ?nomeata? Breitner
  mail at joachim-breitner.de ? http://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/ghc-devs/attachments/20130818/7ecd48ed/attachment.pgp>

Reply | Threaded
Open this post in threaded view
|

Wired-in type class

Simon Peyton Jones
In reply to this post by Joachim Breitner-2
| Is there any reason to prefer such ?slightly wrong? definitions which
| are overwritten with built-in stuff over simply putting the type
| constructors and functions into GHC.Prim?

Because we must generate executable machine instructions for mkCast, and a real info-table for the NT data constructor.  

GHC.Prim, by contrast, has no associated code whatsoever.

| > * We are only going to allow GHC-derived instances of NT.
|
| Just to be sure: Preventing manual instances is currently not possible
| and such a feature would have to be added to GHC, right?

Well Typable is close.  We are trying to prevent user-defined instances of that.  But generally yes it's a new feature.

Simon