2013-12-20 66 views
1

你好我與Haskell的編程新手,我寫這段代碼:爲什麼程序在double類型下運行良好,而不是float類型?

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 

如果我叫funcfunc 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,代碼工作正常。如果我將P的Float實例替換爲Double實例,代碼將與呼叫func 23.3一起正常工作。爲什麼?

+1

請注意,[沒有真正的理由在Haskell中使用'Float'](http://www.haskell.org/haskellwiki/Performance/Floating_point),所以實際上你應該用'Double'代替實例這種單態限制的麻煩。 – leftaroundabout

回答

4

這是臭名昭着的Monomorphism限制。 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將嘗試使類型與Integer,Double,IO,而不是Integral a => a,Double a => aMonad m => m一起工作。它在任何情況下都不起作用。

+2

不打算解除單態限制:我認爲這是實際上非常有用的罕見情況之一,因爲實際上它使用'Float'幾乎是沒有意義的。 – leftaroundabout

相關問題