Opened 2 years ago
Last modified 2 years ago
#13957 new feature request
Allow deriving multiparameter type classes with representationally equal arguments
Reported by: | Iceland_jack | Owned by: | |
---|---|---|---|
Priority: | normal | Milestone: | |
Component: | Compiler | Version: | 8.0.1 |
Keywords: | deriving | Cc: | |
Operating System: | Unknown/Multiple | Architecture: | Unknown/Multiple |
Type of failure: | None/Unknown | Test Case: | |
Blocked By: | Blocking: | ||
Related Tickets: | Differential Rev(s): | ||
Wiki Page: |
Description (last modified by )
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 Identity
s with I
s
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.
Change History (5)
comment:1 Changed 2 years ago by
comment:2 Changed 2 years ago by
Description: | modified (diff) |
---|
comment:3 follow-up: 4 Changed 2 years ago by
This doesn't strike me as a very good idea, for a simple reason: it's quite possible you might also have instance SIEVE I (->)
in scope, which might behave differently from instance SIEVE Identity (->)
. Allowing this sort of thing would make deriving with MPTCs very unpredictable.
comment:4 Changed 2 years ago by
We cannot both have
SIEVE I (->)
and SIEVE Identity (->)
if we assume a functional dependency, similar to #13404 where an analogous example would compile
class SIEVE p where type SIEVE_ty p :: Type -> Type sIEVE :: p a b -> (a -> SIEVE_ty p b) instance SIEVE (->) where type SIEVE_ty (->) = Identity sIEVE :: (a -> b) -> (a -> Identity b) sIEVE f = f >>> Identity newtype ARR a b = ARR (a -> b) deriving newtype SIEVE
ignore
comment:5 Changed 2 years ago by
Keywords: | deriving added |
---|
TODO What if the argument order of
SIEVE
were reversed, as with Sieve.. let's find a way to allow deriving that as well.