【发布时间】:2015-01-13 06:26:19
【问题描述】:
我已经为 Rational 编写了一个包装类型,它使用 NaN 除以零,而不是使程序崩溃。代码编译没有错误或警告。这是(希望是全部)相关代码:
data SafeRational =
SRatio Rational |
SRatioNaN
instance Show (SafeRational) where
show (SRatio x) = show . fromRational $ x
show SRatioNaN = "NaN"
instance Num (SafeRational) where
(+) (SRatio a) (SRatio b) = SRatio (a+b)
(+) _ _ = SRatioNaN -- Good?
(*) (SRatio a) (SRatio b) = SRatio (a*b)
(*) _ _ = SRatioNaN
signum (SRatio a) = SRatio (signum a)
signum SRatioNaN = SRatio 0
abs (SRatio a) = SRatio (abs a)
abs SRatioNaN = SRatioNaN
fromInteger a = SRatio (fromInteger a)
instance Enum (SafeRational) where
fromEnum (SRatio x) = fromEnum x
fromEnum SRatioNaN = 0
toEnum x = SRatio $ toEnum x
instance Fractional (SafeRational) where
(/) (SRatio a) (SRatio b)
| b == 0 = SRatioNaN
| otherwise = SRatio (a / b)
fromRational a = SRatio a
当我尝试将负字面数字“转换”为SafeRational 时出现问题。 Haskell 挂起,就好像它进入了一个无限的回归。正数和零的行为并不奇怪,只有低于零的数字。因为我使用 Haskell 作为数学工具,所以我不经常玩类声明,恐怕我不知道如何调试问题。有人能解释一下吗?
*GHCi> 0-2 :: SafeRational -- makes Haskell sad
_
【问题讨论】:
-
提示 1:查看您对
Num的定义:您如何期望 Haskell 仅使用您提供的定义来计算减法?提示 2:如果您使用 GHC 7.8+,请打开所有警告 (-Wall)。 -
请注意,在documentation for
Num中,它说:“最小完整定义:(+), (*), abs, signum, fromInteger, (negate | (-))。 -
那么 Haskell 会通过添加负数来产生负数吗?那是回归吗?为什么没有警告!另外,我使用 7.6.3。
-
不,问题是因为您需要提供
negate或(-)的定义,以便可以通过默认定义自动计算另一个。但是由于你没有定义任何一个,Haskell 将调用(-)的默认定义,它调用negate的默认定义,它调用(-)的相同默认定义,无限......跨度> -
他们不是在最新的 GHC 中添加了一个编译指示来捕获这样的案例吗?