Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Data Constructor promotion in GHC-7.6

I had this code:

class SymbolSet tpe where
  data Symbol tpe :: *

data SSet tpe where
  Identity :: tpe -> SSet tpe
  And :: SSet tpe -> Symbol tpe -> SSet tpe

class HasElem a b where

instance (SymbolSet tpe) => HasElem (And (Identity tpe) s) s
instance (HasElem sset s) => HasElem (And sset s) s

which was compiling in GHC-7.4. However on moving to GHC-7.6 it started giving compilation errors:

'And' of tpe `forall tpe. tpe -> Symbol * tpe -> SSet tpe' is not promotable

on digging through the docs, I found a new clause added to "Datatype Promotion" pages in GHC-7.6 vs GHC-7.4

We do not promote datatypes whose constructors are kind polymorphic, involve constraints, or use existential quantification.

My question is:

  1. What is the rationale behind not promoting such constructors?
  2. What would be the correct way of doing it?
like image 601
rabisg Avatar asked Nov 09 '13 11:11

rabisg


1 Answers

You didn't say which version of GHC 7.6 you were using or include which extensions you have on, so I'm guessing a bit.

This ticket seems to answer your question 1, although I don't totally understand the problem myself. In your particular example, I think SSet isn't promotable because one of its arguments (Symbol tpe) is an associated type which brings with it the SymbolSet constraint.

If I move Symbol out of the class we get the type promoted, however now we get kind mismatch errors:

{-# LANGUAGE DataKinds , TypeFamilies , GADTs , MultiParamTypeClasses #-}
class SymbolSet tpe where
  -- data Symbol tpe :: *
data Symbol tpe :: *
-- ...

I can get the whole shebang to compile by adding kind signatures to HasElem:

{-# LANGUAGE DataKinds , TypeFamilies , GADTs , MultiParamTypeClasses, FlexibleInstances  #-}
class SymbolSet tpe where
-- MOVED OUT OF CLASS:
data Symbol tpe :: *

data SSet tpe where
  Identity :: tpe -> SSet tpe
  And :: SSet tpe -> Symbol tpe -> SSet tpe

-- ADDED KIND SIGNATURES:
class HasElem (a :: SSet *) (b :: Symbol *) where

instance (SymbolSet tpe) => HasElem (And (Identity tpe) s) s
instance (HasElem sset s) => HasElem (And sset s) s

I don't really understand your code so that may not work for you.

like image 196
jberryman Avatar answered Nov 16 '22 23:11

jberryman