我试图在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实例的所有示例都使用相同的格式。这个错误是什么?
答案 0 :(得分:4)
您的代码存在多个问题。
Ord
实例。您尝试定义的内容会产生非常违反直觉的结果,例如-2 > -1
。一个更合理的实例只会比较实际部分,但如果它们相等则会出现问题。你的条款不必要地复杂化。
在不等式的两边取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
如上所述,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
0
但1
LT
或GT
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)
两个条款中的括号不均衡。你错过了一个亲密的人。