使用“default”声明进行重载数值运算

时间:2013-09-29 08:17:50

标签: haskell

我尝试在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:我已经在一周前就Haskell-Cafe提出了这个问题:

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

但由于我没有得到答案,我在这里提出这个问题。

1 个答案:

答案 0 :(得分: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 )