【发布时间】:2020-11-26 20:18:44
【问题描述】:
我做了以下类来在不同的温度类型之间进行转换:
data Temp = Kelvin Float | Celsius Float |Fahrenheit Float deriving Show
conversionKelvin:: Temp -> Temp
conversionKelvin (Celsius x) = Kelvin (x + 273.15)
conversionKelvin (Fahrenheit x) = Kelvin((x - 32) * 5/9 + 273.15)
conversionKelvin (Kelvin x) = Kelvin x
conversionCelsius:: Temp -> Temp
conversionCelsius (Kelvin x) = Celsius (x - 273.15)
conversionCelsius (Fahrenheit x) = Celsius((x - 32) * 5/9)
conversionCelsius (Celsius x) = Celsius x
conversionFahrenheit:: Temp -> Temp
conversionFahrenheit (Celsius x) = Fahrenheit (x * 9/5 + 32)
conversionFahrenheit (Kelvin x) = Fahrenheit((x - 273.15)*9/5 + 32)
conversionFahrenheit (Fahrenheit x) = Fahrenheit x
到目前为止一切都很好,但是我想实现实例 Eq 和 Ord。我考虑将每种类型转换为摄氏度,然后查看哪个更大,但我无法通过编译器。 有什么帮助吗?
编辑:这是我实例化 Eq 的尝试:
instance Eq Temp where
a == b = conversionCelsius(a) == conversionCelsius(b)
它可以编译,但它使 haskell 进入某种循环(不打印输出)
【问题讨论】:
-
您是如何实现
instance Eq的?请注意,浮点计算通常会出现舍入错误,因此如果两个值彼此接近,则它们可能会“意外”相等,反之亦然。 -
还需要将
Kelvin转换成Kelvin等 -
@WillemVanOnsem ,记录和更新
-
避免舍入问题的一种方法是将固定精度的
Float替换为任意精度的精确Rational(来自Data.Ratio),然后使用fromRational转换为固定精度精确到最后。否则,例如,将温度从摄氏转换为华氏并返回不一定会产生与(==)相等的值:let { x = 1 :: Rational; } in (x, ((x * 9/5 + 32.0) - 32.0) * 5/9)产生完全相同的值(1 % 1, 1 % 1),但使用Float/Double会产生不等值(1.0,0.9999996)/(1.0,0.9999999999999984). -
考虑将每个温度存储在同一单位(可能是开尔文)中,并且仅为显示目的与其他单位进行转换。您可能会使用 温度而不是创建或显示它们所需的温度,如果一切都立即归一化为开尔文,
Eq和Ord是微不足道且可推导的。
标签: haskell