Skip to content

Allow deriving multiparameter type classes with representationally equal arguments

This currently works

{-# Language DerivingStrategies, MultiParamTypeClasses, FunctionalDependencies, GeneralizedNewtypeDeriving #-}

import Data.Kind
import Data.Functor.Identity

class SIEVE f p | p -> f where
  sIEVE :: p a b -> a -> f b

instance SIEVE Identity (->) where
  sIEVE = (Identity .)

newtype ARR a b = ARR (a -> b)
  deriving newtype 
    (SIEVE Identity)

But what if I want a Sieve I ARR instance, for newtype I a = I a (which is representationally equal to newtype Identity a = Identity a)?

{-# Language DerivingStrategies, MultiParamTypeClasses, FunctionalDependencies, GeneralizedNewtypeDeriving, RankNTypes, TypeApplications, ScopedTypeVariables, InstanceSigs #-}

import Data.Kind
import Data.Functor.Identity
import Data.Coerce

class SIEVE f p | p -> f where
  sIEVE :: p a b -> a -> f b

instance SIEVE Identity (->) where
  sIEVE = (Identity .)

newtype ARR a b = ARR (a -> b)
  deriving newtype
    (SIEVE I)

newtype I a = I a

generating the following code (this is basically to code generated before, except replacing some Identitys with Is

instance SIEVE I ARR where
  sIEVE :: forall a b. ARR a b -> (a -> I b) 
  sIEVE
    = coerce
      @((a -> b) -> a -> Identity b)
      @(ARR a b  -> a -> I b)
      sIEVE

GHC should be able to recover Identity due to the functional dependency.

Edited by Icelandjack
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information