为什么Haskell会在我的类型上输入一个文字?

bim*_*mmo 1 haskell casting

我为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)

pha*_*dej 8

即使没有启用任何警告,我在将片段加载到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警告提示,您(不必要的,丢失信息)转换RationalDouble之间.


(+) _ _                     = 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