【问题标题】:Custom Ord instance hangs on lists自定义 Ord 实例挂在列表上
【发布时间】:2012-05-05 18:28:37
【问题描述】:
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/(&gt;=)/(&gt;)/g,它不会挂在第一对,但仍然会挂在第二对:

*Main> (Monomial 1 [("x",2)]) > (Monomial (-1) [])
True
*Main> (Monomial 1 [("x",2)]) < (Monomial (-1) [])
/* Computation hangs here */

虽然标准规定Eq instance 的最小声明为$compare$$(&gt;=)$

这里可能有什么问题? (>=) 在列表上似乎工作得很好。

【问题讨论】:

  • type Variable = String,对吗?如果你定义 compare 而不是 (&gt;=) 会发生什么?
  • 它确实有效。谢谢。

标签: haskell typeclass


【解决方案1】:

简答:
您需要提供(&lt;=)compare 才能完整定义Ord,而不是(&gt;=)

更长的解释:
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(&lt;=)compare。由于您只提供了(&gt;=),因此您还没有提供完整的定义,因此某些方法会循环。您可以通过例如修复它更改您的实例以提供 compare

instance Ord Monomial where
  compare = compare `on` m_powers

【讨论】:

  • instance Eq Monomial 就在instance Ord Monomial 的下方,我在那里定义了 (==)。
  • @FrancisDrake:是的,我只是以Eq 为例,因为它更简单。阅读我的其余答案。
  • 你已经成功了,但它隐藏在许多不必要的绒毛之间。答案很简单“Ord 的最小完整定义是&lt;=,而不是&gt;=”。我认为没有必要就“最小完整定义”的含义进行这么大的讲座。
【解决方案2】:

让我们看看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

所以,如果你只提供上述&gt;===,那么你就有麻烦了,因为:

  • &gt; 定义为 compare

但是

  • compare 定义为 &lt;=
  • &lt;= 定义为 compare

所以你有一个无限循环!

最低定义必须定义&lt;=compare,而不是'>=`。

【讨论】:

    猜你喜欢
    • 2014-07-06
    • 1970-01-01
    • 2018-12-31
    • 1970-01-01
    • 2012-04-13
    • 1970-01-01
    • 2021-07-21
    • 1970-01-01
    • 2017-08-27
    相关资源
    最近更新 更多