在Haskell中复杂数字的Ord实例中导致此错误的原因是什么?

时间:2017-04-13 21:02:31

标签: haskell compare

我试图在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实例的所有示例都使用相同的格式。这个错误是什么?

2 个答案:

答案 0 :(得分:4)

您的代码存在多个问题。

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

    • 在不等式的两边取square root(正值,正如(^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比其他大多数操作贵得多,所以你绝对不想在没有需要的情况下四次调用它。

    • 你不需要在方形表达式周围使用parens,因为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
      

      好的,在这一点上,编译器抱怨的问题非常明显:你错过了两个关闭的问题。或者更确切地说,你有太多的空缺,因为实际上并不需要这些<{1}}甚至比infix 4 ==更弱。

      +

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

      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
      
  3. 如上所述,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 不应该产生compare -1 01 LTGT

    EQ

    但是那些守卫是如此标准,你不需要写出来:只需在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 值上再次调用compare(已经定义的Double实例) :

    r

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

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

答案 1 :(得分:2)

两个条款中的括号不均衡。你错过了一个亲密的人。