如何使用``MyType a = Int`替换`Proxy :: Proxy a`和'a`作为幻像类型

时间:2016-05-31 21:57:48

标签: haskell type-inference

在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因为我认为没有任何含糊之处。我做错了什么?

1 个答案:

答案 0 :(得分:4)

类型同义词完全等同于它们的扩展:R Int ~ R Bool ~ R Char ~ Int。所以,你实际上使用的是

类型
f :: forall a. MyType a => Int -> Int

本质上是不明确的,因为类型变量a仅用于约束。

特别是,如果Tdatanewtype,则编译器可以简化类型等式约束T a ~ T b并推导a ~ b

对于类型族,这不再是真的,因为它们可以是非单射的(虽然有一个GHC 8.0扩展可以正确处理注入)。

对于类型同义词,一般情况下也不是这样。鉴于T a ~ T b,我们会继续扩展同义词T,然后再继续:如果ab在此步骤中消失,则无法推断出它们。