John, can you please document your implementation of classes a bit? I'm trying to implement class aliases... we #haskellers are getting sick of having no such mechanism to play around with... but it would be a lot easier if I understood the module FrontEnd.Class.
On Fri, Mar 07, 2008 at 11:27:48PM -0500, Samuel Bronson wrote:
John, can you please document your implementation of classes a bit? I'm trying to implement class aliases... we #haskellers are getting sick of having no such mechanism to play around with... but it would be a lot easier if I understood the module FrontEnd.Class.
Well, there are two parts to classes in jhc. There is the Front End, which has to typecheck them, keep track of instances and so forth, and the back end, which generates the code for them. Oddly enough, due to the way jhc implements classes, there is no need for the two to communicate :). Since jhc examines the type variables directly, after type checking the class contexts on haskell functions are just discarded when converting to jhc core. For class aliases, you just need to worry about the front end, which, unfortunately is the less clean of the two. The design evolved directly from hatchet, which evolved from the THIH paper[1]. So, understanding that paper might be a good place to start, however you should not need to touch the type checker at all for class aliases so they can actually be quite easy to implement. The information about each class is collected in a FrontEnd.Class.ClassRecord, a 'ClassHierarchy' is just a bunch of class records. when reading in multiple files, their class hierarchies are combined, which simply means combining the instances. what actually happens in the compiler is: a class definition module Main where class Foo a where foo :: a -> Int produces the following bit of core (written in psuedo-haskell) {-# NOINLINE foo #-} Main.foo :: forall a . a -> Int Main.foo = error "Placeholder" as far as everything else is concerned, this is just another routine like any other, since it is never inlined, the fact that its body is 'error' is never exposed. an instance instance Foo Char where foo c = ord c produces the following core Instance@.Main.Foo.foo.Prelude.Char :: Char -> Int Instance@.Main.Foo.foo.Prelude.Char c = ord c {-# RULES "foo/char/instance" Main.foo Char = Instance@.Main.Foo.foo.Prelude.Char #-} (note the explicity application of Main.foo to Char in the head of the rule, haskell hides these applications, the 'forall a' in foo's type signature is how you know it is secretly there) now, whenever Main.foo is called at a Char, it gets replaced with the appropriate instance method. before final compilation, all the RULES attached to any placeholder are turned into an explicit case on the type variable. This mechanism also allows SUPERSPECIALIZE and allows for 'run time rules', though that has not been explored. Umm.. I guess I got sidetracked from class aliases... For those what you want to do is add a new type of 'ClassRecord' that encodes all the information about a class alias, then in the front end (the desugarer is probably easiest, but in the type checker will probably allow better error messages) when you come across a class alias, expand it to its underlying class via the class alias rules. you should not need to modify anything other than the frontend for that, though a few things will have to be taught to ignore the new ClassAlias entries in ClassHierarchy. John -- John Meacham - ⑆repetae.net⑆john⑈
On 3/10/08, John Meacham
what actually happens in the compiler is:
a class definition
module Main where class Foo a where foo :: a -> Int
produces the following bit of core (written in psuedo-haskell)
{-# NOINLINE foo #-} Main.foo :: forall a . a -> Int Main.foo = error "Placeholder"
as far as everything else is concerned, this is just another routine like any other, since it is never inlined, the fact that its body is 'error' is never exposed.
an instance
instance Foo Char where foo c = ord c
produces the following core
Instance@.Main.Foo.foo.Prelude.Char :: Char -> Int Instance@.Main.Foo.foo.Prelude.Char c = ord c
{-# RULES "foo/char/instance" Main.foo Char = Instance@.Main.Foo.foo.Prelude.Char #-}
Hmm. What should I name default implementations?
On Mon, Mar 10, 2008 at 01:50:09PM -0400, Samuel Bronson wrote:
On 3/10/08, John Meacham
wrote: instance Foo Char where foo c = ord c
produces the following core
Instance@.Main.Foo.foo.Prelude.Char :: Char -> Int Instance@.Main.Foo.foo.Prelude.Char c = ord c
{-# RULES "foo/char/instance" Main.foo Char = Instance@.Main.Foo.foo.Prelude.Char #-}
Hmm. What should I name default implementations?
Those are named 'Instance@.Main.Foo.foo.default' and have the type 'forall a . a -> Int' . A default method always exists, even if it is just an error saying no default method was supplied. RULES are generated for the default methods as well in the same fashion. John -- John Meacham - ⑆repetae.net⑆john⑈
On 3/10/08, John Meacham
On Mon, Mar 10, 2008 at 01:50:09PM -0400, Samuel Bronson wrote:
On 3/10/08, John Meacham
wrote: instance Foo Char where foo c = ord c
produces the following core
Instance@.Main.Foo.foo.Prelude.Char :: Char -> Int Instance@.Main.Foo.foo.Prelude.Char c = ord c
{-# RULES "foo/char/instance" Main.foo Char = Instance@.Main.Foo.foo.Prelude.Char #-}
Hmm. What should I name default implementations?
Those are named 'Instance@.Main.Foo.foo.default' and have the type 'forall a . a -> Int' . A default method always exists, even if it is just an error saying no default method was supplied. RULES are generated for the default methods as well in the same fashion.
Well, I meant the additional default methods offered by class aliasses... and what can I do to keep track of what the proper method name is so I can generate the RULES later...
On Mon, Mar 10, 2008 at 07:52:34PM -0400, Samuel Bronson wrote:
Those are named 'Instance@.Main.Foo.foo.default' and have the type 'forall a . a -> Int' . A default method always exists, even if it is just an error saying no default method was supplied. RULES are generated for the default methods as well in the same fashion.
Well, I meant the additional default methods offered by class aliasses... and what can I do to keep track of what the proper method name is so I can generate the RULES later...
you can use 'FrontEnd.Class.instanceName' and 'FrontEnd.Class.defaultInstanceName' for generating appropriate names. since class aliases desugar to normal instances, you should not need to create any new rules at all. John -- John Meacham - ⑆repetae.net⑆john⑈
On 3/10/08, John Meacham
On Mon, Mar 10, 2008 at 07:52:34PM -0400, Samuel Bronson wrote:
Those are named 'Instance@.Main.Foo.foo.default' and have the type 'forall a . a -> Int' . A default method always exists, even if it is just an error saying no default method was supplied. RULES are generated for the default methods as well in the same fashion.
Well, I meant the additional default methods offered by class aliasses... and what can I do to keep track of what the proper method name is so I can generate the RULES later...
you can use 'FrontEnd.Class.instanceName' and 'FrontEnd.Class.defaultInstanceName' for generating appropriate names. since class aliases desugar to normal instances, you should not need to create any new rules at all.
Eh? Won't that generate the same name as before? Or were you thinking it would just combine the alias' name with local component of the method name -- which won't work if the alias expands to classes which have methods of the same name. Which COULD happen, and should work.
On Mon, Mar 10, 2008 at 08:27:20PM -0400, Samuel Bronson wrote:
Eh? Won't that generate the same name as before? Or were you thinking it would just combine the alias' name with local component of the method name -- which won't work if the alias expands to classes which have methods of the same name. Which COULD happen, and should work.
Ah, yeah you should probably include the class alias name in there. as in something like ClassAlias@.[Module].[AliasName].[method] John -- John Meacham - ⑆repetae.net⑆john⑈
On Mon, Mar 10, 2008 at 9:32 PM, John Meacham
On Mon, Mar 10, 2008 at 08:27:20PM -0400, Samuel Bronson wrote:
Eh? Won't that generate the same name as before? Or were you thinking it would just combine the alias' name with local component of the method name -- which won't work if the alias expands to classes which have methods of the same name. Which COULD happen, and should work.
Ah, yeah you should probably include the class alias name in there. as in something like
ClassAlias@.[Module].[AliasName].[method]
But how to tell where the alias name ends and the method name begins? The method name will need to be qualified, won't it?
On Tue, Mar 11, 2008 at 08:17:43AM -0400, Samuel Bronson wrote:
On Mon, Mar 10, 2008 at 9:32 PM, John Meacham
wrote: On Mon, Mar 10, 2008 at 08:27:20PM -0400, Samuel Bronson wrote:
Eh? Won't that generate the same name as before? Or were you thinking it would just combine the alias' name with local component of the method name -- which won't work if the alias expands to classes which have methods of the same name. Which COULD happen, and should work.
Ah, yeah you should probably include the class alias name in there. as in something like
ClassAlias@.[Module].[AliasName].[method]
But how to tell where the alias name ends and the method name begins? The method name will need to be qualified, won't it?
You may need to do something like that. In any case you should never parse existing names to pull out the info about it, you should just call 'classAliasDefaultName alias method' and use the result. As in, I never need to look at a name to find out it is an instance, I Just know that the result of 'instanceName' will be a valid existing name of the right type so I can refer to it directly. The actual format of the name would never occur anywhere in code other than the 'classAliasDefaultName' function so it would be pretty easy to change later in any case. John -- John Meacham - ⑆repetae.net⑆john⑈
On 3/11/08, John Meacham
On Tue, Mar 11, 2008 at 08:17:43AM -0400, Samuel Bronson wrote:
On Mon, Mar 10, 2008 at 9:32 PM, John Meacham
wrote:
ClassAlias@.[Module].[AliasName].[method]
But how to tell where the alias name ends and the method name begins? The method name will need to be qualified, won't it?
You may need to do something like that.
In any case you should never parse existing names to pull out the info about it, you should just call 'classAliasDefaultName alias method' and use the result. As in, I never need to look at a name to find out it is an instance, I Just know that the result of 'instanceName' will be a valid existing name of the right type so I can refer to it directly.
The actual format of the name would never occur anywhere in code other than the 'classAliasDefaultName' function so it would be pretty easy to change later in any case.
Well, I wasn't planning to try and parse it, but I think your suggested way could lead to duplicates, regardless of whether you meant for the names to have been qualified or not (though in different ways in each case, of course, and if qualified these conflicts would be much less likely...)
participants (2)
-
John Meacham -
Samuel Bronson