考虑代码段
{-# 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 a where
Monadify f (a -> r) = a -> Monadify f r
Monadify f a = f a
class Sig sig where
monadify :: Monad m => Proxy sig -> m () -> Monadify m sig
我没有给出任何实例,但示例用法是f :: Int -> String -> Bool, monadify' f :: Int -> String -> IO Bool
。
未能通过以下错误消息进行类型检查:
Couldn't match expected type ‘Monadify m sig’
with actual type ‘Monadify m0 sig0’
NB: ‘Monadify’ is a type function, and may not be injective
The type variables ‘m0’, ‘sig0’ are ambiguous
In the ambiguity check for the type signature for ‘monadify'’:
monadify' :: forall (m :: * -> *) sig.
(Monad m, Sig sig) =>
Monadify m sig
To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
In the type signature for ‘monadify'’:
monadify' :: forall m sig. (Monad m, Sig sig) => Monadify m sig
直觉上我会说应该进行类型检查,但GHC会被类型系列混淆,类型系列没有注释为内射(我宁愿不向后兼容)。它可以从m ()
和Proxy
恢复原像,所以我真的不知道这里有什么问题。
修改
正如错误消息所示,我可以投入AllowAmbiguousTypes
,在我的情况下修复所有问题。但我不知道使用该扩展的后果,而且我宁愿知道为什么我的例子没有进行类型检查。
我觉得这与统一者首先尝试统一Monadify m sig
有关,从而推断它无法证明sig
和m
s是相同的。虽然统一者只需要查看传递的参数就知道它们是相同的,所以这可能是AllowAmbiguousTypes
帮助的地方。
答案 0 :(得分:4)
问题在于monadify'
,而不是monadify
。
假设您正在呼叫
monadify' :: forall m sig. (Monad m, Sig sig) => Monadify m sig
这里没有代理,所以在不假设Monadify
内射的情况下,编译器不可能知道应该实例化m,sig
。还需要了解应该使用(Monad m, Sig sig)
的实例。
尝试使用
monadify' :: forall m sig. (Monad m, Sig sig)
=> Proxy m -> Proxy sig -> Monadify m sig
另请注意,Monadify
不是 injective:
Monadify ((->) Bool) (IO Char) ~ Bool -> IO Char
Monadify IO (Bool -> Char) ~ Bool -> IO Char
如果您使用AllowAmbiguousTypes
,则以下内容不会输入检查:
test :: forall m sig. (Monad m, Sig sig)
=> Proxy sig -> Proxy m -> Monadify m sig
test t _ = monadify' t
-- Type variable m0 is ambiguous
我们可以通过传递显式类型参数m
来修复它:
test :: forall m sig. (Monad m, Sig sig)
=> Proxy sig -> Proxy m -> Monadify m sig
test t _ = monadify' @ m t
就个人而言,我尝试删除所有代理并改为使用类型参数,因为我发现它更清晰,即使这需要不明确的类型。