我做了以下类来在不同的温度类型之间进行转换:
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 Temp where
a == b = conversionCelsius(a) == conversionCelsius(b)
这是因为比较a == b
在两个Temp
之间,而比较conversionCelsius(a) == conversionCelsius(b)
又在两个Temp
之间,所以我们永远递归。
要停止递归,您至少需要有一个基本情况,其中Temp
s 之间的比较是通过比较Float
s 来完成的。一个可能的解决方案如下。
instance Eq Temp where
Celsius x == Celsius y = x == y
a == b = conversionCelsius a == conversionCelsius b
这将直接比较摄氏温度,比较它们的Float
值。其他温度在递归之前转换为摄氏度。递归后,我们将立即找到基本情况,因此递归结束。
我认为您首先还需要将Kelvin
转换为Kelvin
,等等:
conversionKelvin:: Temp -> Temp
conversionKelvin (Celsius x) = Kelvin (x + 273.15)
conversionKelvin (Fahrenheit x) = Kelvin((x - 32) * 5/9 + 273.15)
conversionKelvink@(Kelvin _) = k
至于Eq
实例,您确实可以首先将两个温度转换为相同的单位(无论该单位是什么),然后检查它们是否相等:
instance Eq Temp where
a == b | ~(Kelvinka) <- conversionKelvin a, ~(Kelvinkb) <- conversionKelvin b =ka == kb
话虽如此,使用Float
s 进行的计算通常会导致舍入误差。因此,这意味着两个相同的Temp
可以被认为是不同的,两个略有不同的Temp
可以被认为是相同的。
你也可以实现一个函数toKelvin :: Temp -> Float
,因为结果的单位很清楚:
toKelvin :: Temp ->Float
toKelvin (Celsius x) = x + 273.15
toKelvin (Fahrenheit x) = (x - 32) * 5/9 + 273.15
toKelvin(Kelvin k) = k
然后使用:
instance Eq Temp where
a == b =toKelvin a==toKelvin kb
如何为您的表示选择一个普通形式,派生Eq
实例
type Temp :: Type
newtype Temp = Celsius Float
deriving
newtype Eq
但随后为不同的单位创建模式同义词
pattern Kelvin :: Float -> Temp
pattern Kelvin kelvin <- Celsius (celsiusToKelvin -> kelvin)
where Kelvin kelvin = Celsius (kelvinToCelsius kelvin)
pattern Fahrenheit :: Float -> Temp
pattern Fahrenheit fahrenheit <- Celsius (celsiusToFahrenheit -> fahrenheit)
where Fahrenheit fahrenheit = Celsius (fahrenheitToCelsius fahrenheit)