在Haskell中使用类型时,我想出了以下内容:
class MyType a where typeVal :: Proxy a -> Int
instance MyType Int where typeVal _ = 1
instance MyType Char where typeVal _ = 2
g :: MyType a => Int -> Proxy a -> Int
g x p = x + typeVal p
这可以按预期工作。然后,我认为也许我可以让函数返回一个自定义类型,而不是传递Proxy
:
{-# LANGUAGE ScopedTypeVariables #-}
type R a = Int
f :: forall a. MyType a => Int -> R a
f x = x + typeVal (Proxy :: Proxy a)
我认为这样可行,但事实并非如此。我收到错误:
Could not deduce (MyType a0)
from the context (MyType a)
bound by the type signature for f :: MyType a => Int -> R a
The type variable ‘a0’ is ambiguous
In the ambiguity check for the type signature for ‘f’:
f :: forall a. MyType a => Int -> R a
To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
In the type signature for ‘f’: f :: MyType a => Int -> R a
我不想启用AllowAmbiguousTypes
因为我认为没有任何含糊之处。我做错了什么?
答案 0 :(得分:4)
类型同义词完全等同于它们的扩展:R Int ~ R Bool ~ R Char ~ Int
。所以,你实际上使用的是
f :: forall a. MyType a => Int -> Int
本质上是不明确的,因为类型变量a
仅用于约束。
特别是,如果T
是data
或newtype
,则编译器可以简化类型等式约束T a ~ T b
并推导a ~ b
。
对于类型族,这不再是真的,因为它们可以是非单射的(虽然有一个GHC 8.0扩展可以正确处理注入)。
对于类型同义词,一般情况下也不是这样。鉴于T a ~ T b
,我们会继续扩展同义词T
,然后再继续:如果a
和b
在此步骤中消失,则无法推断出它们。