我为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
Run Code Online (Sandbox Code Playgroud)
当我试图'施放'负数字数时,会出现问题SafeRational.Haskell挂起就好像它已进入无限回归.正数和零不奇怪,只有零以下的数字.因为我使用Haskell作为数学工具,所以我不经常使用类声明,我担心我不知道如何调试问题.有人请解释一下吗?
*GHCi> 0-2 :: SafeRational -- makes Haskell sad
_
Run Code Online (Sandbox Code Playgroud)
即使没有启用任何警告,我在将片段加载到ghci(7.8.3)时也会得到:
SRational.hs:9:10: Warning:
No explicit implementation for
either ‘negate’ or ‘-’
In the instance declaration for ‘Num SafeRational’
Run Code Online (Sandbox Code Playgroud)
即必须定义一个.它们的默认定义是相互递归的:
x - y = x + negate y
negate x = 0 - x
Run Code Online (Sandbox Code Playgroud)
启用后,-Wall您还可以捕获另一个错误:
SRational.hs:26:5: Warning:
Pattern match(es) are non-exhaustive
In an equation for ‘/’:
Patterns not matched:
SRatioNaN _
(SRatio _) SRatioNaN
Run Code Online (Sandbox Code Playgroud)
当你划分任何东西时会发生什么SRatioNaN,例如0 / SRatioNaN?
您可以定义show by:
instance Show (SafeRational) where
show (SRatio x) = show x
show SRatioNaN = "NaN"
Run Code Online (Sandbox Code Playgroud)
作为另一个-Wall警告提示,您(不必要的,丢失信息)转换Rational到Double之间.
(+) _ _ = SRatioNaN -- Good?
Run Code Online (Sandbox Code Playgroud)
是的,但是
SRatio a + SRatio b = SRatio (a + b)
_ + _ = SRatioNan
Run Code Online (Sandbox Code Playgroud)
读得更好(恕我直言).
为什么文字-2被转化为fromInteger (-2 :: Integer)?原因在于Haskell报告(3.4运算符应用程序):
特殊形式-e表示前缀否定,Haskell中唯一的前缀运算符,并且是语法
negate (e).二元-运算符不一定是指-Prelude中的定义; 它可能会被模块系统反弹.但是,一元-将始终引用negatePrelude中定义的函数.-操作符的本地含义与一元否定之间没有联系.
所以-2变成了negate (fromInteger (2 :: Integer)).
这是Haskell的奇怪和讨论的功能:https ://www.haskell.org/haskellwiki/Unary_operator https://ghc.haskell.org/trac/haskell-prime/wiki/NegativeSyntax