Skip to content

allow existential wrapper newtypes

Consider this OO-style thing, a class Compiler, and a most general instance MkCompiler:

class Compiler c where
  getInstalledPackages :: c -> IO [String]

data GHC = GHC { }
data NHC = NHC { }

ghc :: GHC
ghc = GHC { }

nhc :: NHC
nhc = NHC { }

instance Compiler GHC
instance Compiler NHC

data MkCompiler where
  MkCompiler :: Compiler c => c -> MkCompiler

instance Compiler MkCompiler where
  getInstalledPackages (MkCompiler c) = getInstalledPackages c

compilers :: [MkCompiler]
compilers = [MkCompiler ghc, MkCompiler nhc]

There's two language features we want to make this really nice:

  1. Letting us call the data type Compiler rather than MkCompiler. That would mean separating the class and type namespaces.
  2. Letting us derive the Compiler instance for MkCompiler.

For the latter we would want either:

newtype MkCompiler where
    MkCompiler :: Compiler c => c -> MkCompiler
  deriving Compiler

or

data MkCompiler where
    MkCompiler :: Compiler c => c -> MkCompiler
  deriving Compiler

The advantage of the first is that newtype deriving already exists as a concept so that's nice and consistent. The problem is we do not allow newtypes that use existentials. From an implementation point of view, it's clear that the representations cannot be equal because of the need to store the class dictionary. From a semantic point of view however it's not obvious that existentials with class contexts are illegitimate in newtypes. The underlying implementation would of course have to be an extra layer of boxing, so like data but with the pattern match behaviour newtype.

Trac metadata
Trac field Value
Version 6.10.4
Type FeatureRequest
TypeOfFailure OtherFailure
Priority normal
Resolution Unresolved
Component Compiler
Test case
Differential revisions
BlockedBy
Related
Blocking
CC
Operating system
Architecture
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information