为什么程序适用于double类型而不是float类型?

时间:2013-12-20 22:06:25

标签: class haskell types double

嗨,我是haskell编程的新手,我写了这段代码:

f :: a->Bool
f x = True

g :: a->Bool 
g x = False

class P a where
   func :: a->Bool

instance P Integer where
   func x = f x

instance P Float where
   func x = g x

如果我将函数func称为func 23.3,Ghci将返回以下错误:

<interactive>:6:6: Ambiguous type variable a0' in the constraints: (Fractional a0) arising from the literal 23.3' at <interactive>:6:6-9 (P a0) arising from a use of func' at <interactive>:6:1-4 Probable fix: add a type signature that fixes these type variable(s) In the first argument of func', namely 23.3' In the expression: func 23.3 In an equation for it': it = func 23.3

虽然如果我用Integer作为参数调用func,代码工作正常。如果我用Float实例替换P的Double实例,则代码可以与调用func 23.3一起正常工作。为什么?

1 个答案:

答案 0 :(得分:4)

这是臭名昭着的单态限制。 GHCi不知道将23.3转换为具体的类型,并且有多种Fractional a数据类型(特别是DoubleFloat)。

您可以使用

禁用此功能
> :set -XNoMonomorphismRestriction

或者更好

> func (23.3 :: Float)

原因是因为文字23.3的类型为

> :type 23.3
23.3 :: Fractional a => a

而不是像FloatInt这样更具体的类型。这实际上允许您实现自己的类型,可以用数字文字表示(有时是一个方便的技巧)。不幸的是,它给出了一个相当无益的错误信息,让每个初学者都感到困惑。但是,编译器必须具有特定类型,因为您还可以添加

instance P Double where
    func x = undefined

然后它必须决定func的哪个实例用于像23.3这样的文字。最佳做法是仅指定您使用内联的类型,如上所示。

可能之所以它在GHCi中使用Double的原因是因为GHCi有时会尝试将类型强制转换为更方便的东西。这就是为什么你要这样做

> let x = [1..]
> :type x
x :: [Integer]

x应该有(Enum a, Num a) => [a]类型。如果启用了Monomorphism限制(默认情况下),GHCi将尝试使类型与IntegerDoubleIO一起使用,而不是Integral a => a,{{ 1}}或Double a => a。它并不适用于所有情况。