自定义Ord实例挂起列表

时间:2012-05-05 18:28:37

标签: haskell typeclass

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; =)似乎工作得很好。

2 个答案:

答案 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; =`。