Version 2 (modified by guest, 7 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.