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

时间:2015-01-13 06:26:20

标签: 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

当我尝试演员时会出现问题。 SafeRational的负字面数字。 Haskell挂起就好像它已进入无限回归。正数和零不奇怪,只有零以下的数字。因为我使用Haskell作为数学工具,我不经常使用类声明,我担心我不知道如何调试问题。有人请解释一下吗?

*GHCi> 0-2 :: SafeRational       -- makes Haskell sad
_

1 个答案:

答案 0 :(得分:8)

即使没有启用任何警告,我也会在将代码段加载到ghci(7.8.3)时得到:

SRational.hs:9:10: Warning:
    No explicit implementation for
      either ‘negate’ or ‘-’
    In the instance declaration for ‘Num SafeRational’

即。必须定义一个。它们的默认定义是相互递归的:

x - y               = x + negate y
negate x            = 0 - x

同样启用-Wall,你会发现另一个错误:

SRational.hs:26:5: Warning:
    Pattern match(es) are non-exhaustive
    In an equation for ‘/’:
        Patterns not matched:
            SRatioNaN _
            (SRatio _) SRatioNaN

SRatioNaN划分任何内容时会发生什么情况,例如0 / SRatioNaN


其他评论评论:

您可以定义show by:

instance Show (SafeRational) where
    show (SRatio x) = show x
    show SRatioNaN  = "NaN"

当另一个-Wall警告提示时,您(不必要地,丢失信息)会将Rational转换为Double


(+) _ _                     = SRatioNaN -- Good?

是的,但是

SRatio a + SRatio b         = SRatio (a + b)
_ + _                       = SRatioNan

读得更好(恕我直言)。


为什么将文字-2转换为fromInteger (-2 :: Integer)?原因在于Haskell Report(3.4运算符应用程序):

  

特殊形式-e表示前缀否定,Haskell中唯一的前缀运算符,是negate (e)的语法。二元-运算符不一定引用Prelude中-的定义;它可能会被模块系统反弹。但是,一元-将始终引用Prelude中定义的negate函数。 -运算符的本地含义与一元否定之间没有联系。

所以-2转换为negate (fromInteger (2 :: Integer))

这是Haskell的奇怪和讨论的特征:https://www.haskell.org/haskellwiki/Unary_operator https://ghc.haskell.org/trac/haskell-prime/wiki/NegativeSyntax