是什么导致了 Ord 实例中 Haskell 中复数的此错误?



我正在尝试在 Haskell 中为复数实现一个 Ord 实例。我按照我在网上找到的格式来实现 Ord 实例,但我收到一个我不明白的错误。以下是我的实例代码:

instance Ord Complex where
compare (Com x1 y1) (Com x2 y2) 
| (sqrt ((x1^2)+(y1^2))) < (sqrt ((x2^2)+(y2^2)) = -1 
| (sqrt ((x1^2)+(y1^2))) == (sqrt ((x2^2)+(y2^2)) = 0 
| otherwise = 1

当我尝试将其加载到GHCI中时,出现此错误:

Complex.hs:45:52: error:
parse error on input `='
Perhaps you need a 'let' in a 'do' block?
e.g. 'let x = 5' instead of 'x = 5'

但是我见过的所有 Ord 实例示例都使用相同的格式。这个错误是什么?

您的代码存在多个问题。

  1. 有充分的理由给复数一个Ord实例。您尝试定义的那个给出了非常违反直觉的结果,例如-2 > -1。一个更合理的实例只会比较真实的部分,但如果它们相等,这是有问题的。
    总而言之,这是您最好不要定义的实例之一。
  2. 您的条款不必要地复杂。

    • 取不平等两侧的平方根(由(^2)确保的正值)没有区别。

      compare (Com x1 y1) (Com x2 y2) 
      | ((x1^2)+(y1^2)) < ((x2^2)+(y2^2) = -1 
      | ((x1^2)+(y1^2)) == ((x2^2)+(y2^2) = 0 
      

      这是一个非常重要的更改,因为sqrt比大多数其他操作要昂贵得多,因此您绝对不想在不需要的情况下调用它四次。

    • 您不需要方形表达式周围的括号,因为infixr 8 ^infixl 6 +绑定得更紧。

      compare (Com x1 y1) (Com x2 y2)
      | (x1^2 + y1^2) < (x2^2 + y2^2 = -1
      | (x1^2 + y1^2) == (x2^2 + y2^2 = 0
      

      好的,在这一点上,编译器抱怨的问题非常明显:你缺少两个结束参数。或者更确切地说,你有太多的开场白,因为实际上这些都不需要(infix 4 ==绑定甚至比+弱)。

      compare (Com x1 y1) (Com x2 y2)
      | x1^2 + y1^2 < x2^2 + y2^2 = -1
      | x1^2 + y1^2 == x2^2 + y2^2 = 0
      

      这开始看起来不错,但仍然有很多冗余:你正在计算不平等的两面两次。这可能不是太多的表现,但它仍然违反了 DRY。

      compare (Com x₁ y₁) (Com x₂ y₂)
      | r₁ < r₂    = -1
      | r₁ == r₂   = 0
      | otherwise  = 1
      where r₁ = x₁^2 + y₁^2
      r₂ = x₂^2 + y₂^2
      
  3. 如前所述,compare不应该屈服于-101,而应该屈服于LTGTEQ

    compare (Com x₁ y₁) (Com x₂ y₂)
    | r₁ < r₂    = LT
    | r₁ == r₂   = EQ
    | otherwise  = GT
    where r₁ = x₁^2 + y₁^2
    r₂ = x₂^2 + y₂^2
    

    但是这些守卫是如此标准,以至于你不需要把它们写出来:只需在r值上再次调用compare(已经定义的Double实例):

    compare (Com x₁ y₁) (Com x₂ y₂) = compare r₁ r₂
    where r₁ = x₁^2 + y₁^2
    r₂ = x₂^2 + y₂^2
    

    您现在还可以再次内联变量:

    compare (Com x₁ y₁) (Com x₂ y₂) = compare (x₁^2 + y₁^2) (x₂^2 + y₂^2)
    

两个子句中的不平衡括号。你错过了一个紧密的括号。

最新更新