Haskell错误:“没有使用'=='产生的实例(Eq Time)

时间:2015-10-22 19:27:49

标签: haskell

我对Haskell很新,我不明白为什么我无法比较这两个变量。 我有这个功能:

nextMinute :: Date -> Time -> DateTime
nextMinute date time = if time == Time 23 59
                       then DateTime (tomorrow date) newDay
                       else DateTime date (timeSucc time)

我收到此错误消息:

Time.hs:88:32:
    No instance for (Eq Time) arising from a use of ‘==’
    In the expression: time == Time 23 59
    In the expression:
      if time == Time 23 59 then
          DateTime date newDay
      else
          DateTime date (timeSucc time)
    In an equation for ‘nextMinute’:
        nextMinute date time
          = if time == Time 23 59 then
                DateTime date newDay
            else
                DateTime date (timeSucc time)

2 个答案:

答案 0 :(得分:6)

您可以只使用模式匹配来代替使用==

nextMinute :: Date -> Time -> DateTime
nextMinute date (Time 23 59) = DateTime (tomorrow date) newDay
nextMinute date time         = DateTime date            (timeSucc time)

Eq添加到Time类型可能很好,但是当模式匹配的解决方案同样出色时,也没有特别需要。

答案 1 :(得分:5)

平等比较在Haskell中有点代码味道。如果您发现自己使用它,请始终考虑是否应该更好地使用模式匹配,如amalloy的答案所示。模式匹配往往更有效,并且即使在完全不可能的情况下(例如在无限长度列表上),通常仍然有效。

除此之外,IMO还有一些类型,你应该更好地避免任何平等假设。这包括代表一些连续物理量的所有类型,例如确实是时间。从数学上讲,两个这样的值是effectively never equal。从更实际的角度来看,您的方法存在这样的风险:如果您以某种方式超过确切的值23:59(例如,在检查日期转换之前添加一分钟和第二个),那么换行将永远不会发生!

因此,我建议仅将这些值与较少/较大的运算符进行比较。

nextMinute :: Date -> Time -> DateTime
nextMinute date time
  | h' >= 24   = DateTime (tomorrow date) newDay
  | otherwise  = DateTime date naïveSucc
 where naïveSucc@(Time h' _) = timeSucc time

事实上,无限长列表上的等式与实数上的等式有很多相同的问题,如果你将它们描述为无限长度的十进制扩展。当然,我们通常使用的数字类型实际上并不是无限精确的,但奇怪的是它常常有助于假装:真的,浮点数会受到各种令人讨厌的不确定性问题的影响,但如果你只是不喜欢&# 39;尝试比较所有数字,但只是一个懒惰的选择,然后你就会很好。

正如dfeuer所言,如果您创建Time实例,还可以将<直接与Ord进行比较。与Eq类似,可以自动导出

data Time = Time { ... }
 deriving (Show, Eq, Ord)

但请注意:记录字段需要按照正确的顺序才能使词典顺序有意义(您不想要9:45 > 10:15!)