Version 2 (modified by 10 years ago) (diff) | ,
---|

## Representing closure-converted types as indexed types

The idea is to use a class

class CC a where data CConv a -- closure converted 'a' to :: a -> CConv a fr :: CConv a -> a

The most interesting instance is that for functions, which reads

data Clo a b = forall e. Clo (c -> a -> b) e class (CC a, CC b) => CC (a -> b) where data CConv (a -> b) = CCArrow (Clo a b) to f = Clo (\_ -> f) () fr (Clo f e) = f e

For all basic types, we want something like the following:

instance CC Int where newtype CConv Int = CCInt Int to = CCInt fr (CCInt x) = x

In fact, we want something like that for all types that are defined in modules that are not closure-converted. Unfortunately, associated *data* types cannot have defaults. (Also note that we use here a `newtype instance`

for a `data`

family. Something, which should be easy to add to GHC's implementation of associated types, but isn't allowed right now.)

### User-defined types

When we encounter a data type definition for `T a1 .. an`

in a closure converted module, we need to generate a `CC (T a1 .. an)`

instance of `CC`

. The right hand side of `CConv (T a1 .. an)`

will have the same form as that of `T`

, but with all data constructors renamed and with all types `t`

replaced by `CConv t`

. If no arrows occur directly or indirectly in the definition of `T`

, we could instead use the same *default* instance as outlined for basic types above, as an optimisation.

### Import and export

To export and import the data constructors of `CConv`

instances, we can just export and import `CConv(..)`

.

### Higher-kinded types

During our brain storming, we thought that we might need `CConv`

on higher-kinds, too - i.e., if we have `CConv (T a1 .. an)`

, we also want `CConv T`

. The idea was that if we have

data U t = forall a. U a (a -> t a) data T a = ...

the translation of `U T`

requires `CConv T`

.

However, I am not so convinced anymore that we really need it (at least as long as disregarding the interaction with non-closure-converted code). After all, we need `CConv`

essentially in two places:

- If we have
`f :: tau`

, we produce`f' :: CConv tau`

. - If we have
`data T = MkT tau`

, we produce`data CConv T = CCMkT (CConv tau)`

.

In both cases, we only apply `CConv`

to tau types. (In GHC's sense of tau types.)

The only place, where that's not the case that I can see at the moment is when the closure-converted module defines (or uses?) constructor classes. Then, we need a corresponding constructor class for `CConv C`

(where the `C`

is the type constructor). This doesn't seem to be a feature that we need to cover in the near future.

In any case, we might be able to use a family of classes (such as with `Typeable`

and we also discussed some tricks we might be able to play with associated synonyms).

### Contexts: 1. dealing with signature contexts

Something we didn't think about much so far is how to closure convert functions that have a class context; so, if we have

inc :: Num a => a -> a inc = (+1)

what is the signature of the closure converted version? We can't use

inc :: CConv (Num a => a -> a)

as associated types don't support that. We probably want

inc :: Num a => CConv (a -> a) -- OR inc :: Num (CConv a) => CConv (a -> a)

As closure conversion happens on Core code, we need to be careful, as the context is not visible as such in the *core view* of types.