import Data.Function (on)
import Data.List (sort)
data Monomial = Monomial
{ m_coeff :: Coefficient
, m_powers :: [(Variable, Power)]
}
deriving ()
instance Ord Monomial where
(>=) = on (>=) m_powers
instance Eq Monomial where
(==) = on (==) m_powers
这是我的代码的摘录,减少到主要尺寸。我们来试试比较:
*Main> (Monomial 1 [("x",2)]) > (Monomial (-1) [])
/* Computation hangs here */
*Main> (Monomial 1 [("x",2)]) < (Monomial (-1) [])
/* Computation hangs here */
另一方面,有趣的是,如果我在实例声明中替换s/(>=)/(>)/g
,它将不会挂在第一对上,但仍然会在第二对:
*Main> (Monomial 1 [("x",2)]) > (Monomial (-1) [])
True
*Main> (Monomial 1 [("x",2)]) < (Monomial (-1) [])
/* Computation hangs here */
虽然标准规定Eq instance
的最小声明为$compare$
或$(>=)$
。
这可能是什么问题?列表上的(&gt; =)似乎工作得很好。
答案 0 :(得分:9)
简答:
您需要提供(<=)
或compare
才能获得Ord
的完整定义,而不是(>=)
。
更长的解释:
Haskell中的类型类通常具有根据其他方法实现的某些方法的默认实现。然后,您可以选择要实施的项目。例如,Eq
如下所示:
class Eq a where
(==), (/=) :: a -> a -> Bool
x /= y = not (x == y)
x == y = not (x /= y)
在这里,您必须实现(==)
或(/=)
,否则尝试使用其中任何一个都会导致无限循环。您需要提供哪些方法通常在文档中列为最小完整定义。
Ord
个实例as listed in the documentation的最小完整定义是(<=)
或compare
。由于您只提供了(>=)
,因此您没有提供完整的定义,因此有些方法会循环。您可以通过例如修复它更改您的实例以改为提供compare
。
instance Ord Monomial where
compare = compare `on` m_powers
答案 1 :(得分:6)
让我们看一下Ord
的默认实例:
class (Eq a) => Ord a where
compare :: a -> a -> Ordering
(<), (<=), (>), (>=) :: a -> a -> Bool
max, min :: a -> a -> a
compare x y = if x == y then EQ
-- NB: must be '<=' not '<' to validate the
-- above claim about the minimal things that
-- can be defined for an instance of Ord:
else if x <= y then LT
else GT
x < y = case compare x y of { LT -> True; _ -> False }
x <= y = case compare x y of { GT -> False; _ -> True }
x > y = case compare x y of { GT -> True; _ -> False }
x >= y = case compare x y of { LT -> False; _ -> True }
-- These two default methods use '<=' rather than 'compare'
-- because the latter is often more expensive
max x y = if x <= y then y else x
min x y = if x <= y then x else y
所以,如果你只提供>=
和==
,那么你就麻烦了,因为:
>
是根据compare
<强>但是强>
compare
是根据<=
<=
是根据compare
所以你有一个无限循环!
最低定义必须定义<=
或compare
,而不是'&gt; =`。