【问题标题】:Why does the program work well with the double type and not with float type?为什么程序适用于 double 类型而不适用于 float 类型?
【发布时间】:2014-01-09 20:24:31
【问题描述】:

你好,我是一个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

如果我使用整数作为参数调用func,代码工作正常。如果我用Double 实例替换P 的Float 实例,则代码在调用func 23.3 时可以正常工作。为什么?

【问题讨论】:

标签: class haskell types double


【解决方案1】:

这是臭名昭著的单态限制。 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) =&gt; [a] 类型时。当您启用单态限制(默认情况下)时,GHCi 将尝试使类型与IntegerDoubleIO 一起工作,而不是Integral a =&gt; aDouble a =&gt; aMonad m =&gt; m。它只是在每种情况下都无法正常工作。

【讨论】:

  • 无意取消单态性限制:我认为这是它真正有用的罕见情况之一,因为实际上使用Float 几乎没有意义。
猜你喜欢
  • 2012-01-22
  • 2020-05-05
  • 1970-01-01
  • 2014-10-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-22
相关资源
最近更新 更多