2013-09-29 29 views
2

我嘗試在Haskell中開發嵌入式特定於領域的語言。 我不想類型簽名作爲::Rational所有的時間,所以我嘗試使用默認 聲明我的類型:使用「默認」聲明重載數字操作

corresponding section in Haskell report

這正常工作在這個簡單的例子:

default (Integer, Double) -- "default default" 

mag :: Float -> Float -> Float 
mag x y = sqrt(x^2 + y^2) 

main = do 

print $ mag 1 1 

事實上,我們獲得sqrt(2)作爲結果。如果我們通過替換默認聲明 :

default() 

,我們得到的編譯錯誤如期望的那樣的2類型是不明確的。

現在讓我們考慮一個更復雜的例子:

{-# LANGUAGE FlexibleInstances #-} 
import Prelude hiding ((^^)) 
import Data.Ratio 

default (Integer, Rational, Double) 

class (Num a) => Foo a where 
    (^^) :: Num b => b -> a -> b 

instance Foo Rational where 
    (^^) x r = x^n 
        where n = 2*numerator r -- dummy calculation 

instance Foo Integer where 
    (^^) x n = x^n 

mag :: Float -> Float -> Float 
mag x y = sqrt(x ^^ 2 + y ^^ 2) 

main = do 
print $ mag 1 1 

我希望它能夠正常工作,但我們得到有關 曖昧類型的2錯誤。 爲什麼? 如何使我的默認聲明工作? 如果我想優先考慮Rational而不是Integer? 事實上,這應該是可能的,因爲我們在下面沒有得到任何錯誤。

$ ghci 
> import Data.Ratio 
> 2::Rational 
2 % 1 

PS1:答案可能與

answer given to a question on Stack Overflow

,但我不知道以何種方式。

PS2:我已經問的問題在一週前就哈斯克爾 - 咖啡:

http://www.haskell.org/pipermail/haskell-cafe/2013-September/108956.html

但正如我沒有獲得答案,我在這裏問的問題。

回答

1

Haskell對於類型默認類型非常保守:它只選擇在Prelude中定義的類的默認實例。在你的情況下,對文字2的類型有一個Foo約束,所以編譯器不會爲它選擇一個默認實例。

您可以通過編寫單形函數來以語法上較輕的方式聲明類型。例如,以下編譯沒有錯誤:

rat :: Rational -> Rational 
rat x = x 

mag :: Float -> Float -> Float 
mag x y = sqrt(x ^^ rat 2 + y ^^ rat 2) 
+0

感謝散熱器爲您的答案。是不是typeclass約束而不是指數(在我的例子中,等於'2')?實際上類型類型'Foo'的類型變量'a'對應於指數,而不是基數。無論如何,如果我是對的,原因是因爲'^^'的正確參數有一個類型類型約束'Foo',它不是標準類型類型,因此不可能有默認類型。我對嗎?感謝您的解決方案。 – user2827908

+0

@ user2827908是的,沒錯。我修正了文字。 – Heatsink