haskell - Types don't unify using a type class and a type family -


consider snippet

{-# language scopedtypevariables #-} {-# language typefamilies #-}  import data.proxy  monadify' :: forall m sig. (monad m, sig sig) => proxy sig -> monadify m sig monadify' p = monadify p (return () :: m ())  type family monadify f   monadify f (a -> r) = -> monadify f r   monadify f = f  class sig sig     monadify :: monad m => proxy sig -> m () -> monadify m sig 

i've given no instances, example usage f :: int -> string -> bool, monadify' f :: int -> string -> io bool.

it fails typecheck following error message:

couldn't match expected type ‘monadify m sig’             actual type ‘monadify m0 sig0’ nb: ‘monadify’ type function, , may not injective type variables ‘m0’, ‘sig0’ ambiguous in ambiguity check type signature ‘monadify'’:   monadify' :: forall (m :: * -> *) sig.                (monad m, sig sig) =>                monadify m sig defer ambiguity check use sites, enable allowambiguoustypes in type signature ‘monadify'’:   monadify' :: forall m sig. (monad m, sig sig) => monadify m sig 

intuitively i'd should typecheck, ghc gets confused type family, not annotated injective (i'd rather not backwards compatibility). recover preimage m () , proxy though, don't know what's problem here.

edit:

as error message suggests, throw in allowambiguoustypes, in case fixes problems. don't know consequences of using extension, plus i'd rather know why example doesn't typecheck.

i have feeling has unifier first trying unify monadify m sigs, thereby inferring can't prove sigs , ms identical. although unifier needed @ passed arguments know identical, might allowambiguoustypes helps.

the problem monadify', not monadify.

suppose calling

monadify' :: forall m sig. (monad m, sig sig) => monadify m sig 

here there no proxies around so, without assuming monadify injective, impossible compiler know m,sig should instantiated to. needed understand instances (monad m, sig sig) should used.

try instead working with

monadify' :: forall m sig. (monad m, sig sig)            => proxy m -> proxy sig -> monadify m sig 

also note monadify not injective:

monadify ((->) bool) (io char)      ~ bool -> io char monadify io          (bool -> char) ~ bool -> io char 

if use allowambiguoustypes following not type check:

test :: forall m sig. (monad m, sig sig)      => proxy sig -> proxy m -> monadify m sig test t _ = monadify' t -- type variable m0 ambiguous 

we can fix passing explicit type argument m:

test :: forall m sig. (monad m, sig sig)      => proxy sig -> proxy m -> monadify m sig test t _ = monadify' @ m t 

personally, i'd try remove proxies , use type arguments instead, since find cleaner, if requires ambiguous types.


Comments