我正在尝试在 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 实例示例都使用相同的格式。这个错误是什么?
您的代码存在多个问题。
- 有充分的理由不给复数一个
Ord
实例。您尝试定义的那个给出了非常违反直觉的结果,例如-2 > -1
。一个更合理的实例只会比较真实的部分,但如果它们相等,这是有问题的。
总而言之,这是您最好不要定义的实例之一。 -
您的条款不必要地复杂。
-
取不平等两侧的平方根(由
(^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
-
-
如前所述,
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
但是这些守卫是如此标准,以至于你不需要把它们写出来:只需在
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)
两个子句中的不平衡括号。你错过了一个紧密的括号。