使用可用的类实例解决类型歧义

时间:2015-04-22 02:25:27

标签: haskell typeclass ambiguity ambiguous

给出以下代码:

import Data.Word

data T = T deriving (Eq, Show)

class    C a      where f :: a -> ()
instance C T      where f _ = ()
instance C Word16 where f _ = ()

main = return $ f 0x16

GHC抱怨它无法推断出文字0x16的类型应该是错误:

No instance for (Num a0) arising from the literal ‘22’
The type variable ‘a0’ is ambiguous

很容易理解为什么会这样--Haskell允许数字文字属于任何具有Num实例的类型,在这里我们无法消除文字{{1 (或22)应该是。

作为一个人类阅读也清楚我想要做的事情 - 只有一个类0x16的可用实例满足C约束,所以显然我打算使用那个因此Num应被视为0x16

我知道有两种方法可以修复它:使用其类型注释文字:

Word16

或定义一个基本上为您做注释的函数:

main = return $ f (0x16 :: Word16)

我尝试了第三种方法,将w16 x = x :: Word16 main = return $ f (w16 0x16) 放在文件的顶部,希望Haskell选择它作为数字文字的默认类型,但我想我误解了{{1应该关键字,因为它不起作用。

我理解类型类是开放的,所以只是因为你可以在上面引用的上下文中做出假设default (Word16)default的唯一数字实例,可能在其他模块中没有。但我的问题是:是否有一些机制可以假设/强制执行该属性,因此可以使用Word16并使Haskell将其数字参数的类型解析为C而无需显式注释在通话现场?

上下文是我正在实现一个EDSL,当我知道我的参数将是f或其他非数字类型时,我宁愿不必包含手动类型提示。如果它让EDSL感觉更自然,我会对一些肮脏的类型/扩展滥用开放!虽然如果解决方案确实涉及顽皮的pragma,我肯定会欣赏在使用它们时我应该警惕的暗示。

1 个答案:

答案 0 :(得分:5)

对于其他任何想知道default的人(我知道我是!)

https://www.haskell.org/onlinereport/haskell2010/haskellch4.html#x10-750004.3

引用第4.3.4节:

  

在发现模糊类型的情况下,如果出现以下情况,则模糊类型变量v是可以违约的:

     
      
  • v仅出现在C v形式的约束中,其中C是一个类,
  •   
  • 这些类中至少有一个是数字类(即Num或Num的子类),
  •   
  • 所有这些类都在Prelude或标准库中定义。
  •   

这就解释了为什么你的default子句被完全忽略了; C不是标准的库类型类。

(至于为什么这是规则......在那里无法帮助你。大概是为了避免破坏任意用户定义的代码。)