Haskell处理负参数

3

尝试对两个值求和,其中只有一个是负数,例如-12:

soma :: Float -> Float -> Float
soma x1 x2 = x1 + x2

结果出现了错误;为什么呢?
<interactive>:10:6:
No instance for (Num (Float -> Float -> Float))
  arising from a use of `-'
Possible fix:
  add an instance declaration for (Num (Float -> Float -> Float))
In the expression: soma - 1 2
In an equation for `it': it = soma - 1 2

2
返回已翻译的文本:-1 - clime
真的尝试一下;没有空间。 - user109964
2
好的,那么应该是(-1),抱歉。 - clime
是的,它能工作,但这是一个糟糕的解决方案;为什么会出错?你曾经见过这个吗? - user109964
4
这是唯一(且好的)解决方案。看看Haskell如何评估表达式(提示:Soma应用于一元负号运算符,并抱怨它不是浮点数)。 - clime
1个回答

14

你应该使用(-1)而不是-1。解析器将你输入的内容解释为 (-) soma (1 2)。换句话说,它试图从soma中减去(1 2)。这行不通,因为subtract函数不接受Float -> Float -> Float。

你希望发生的(并且预期的)是,Haskell将-作为一个一元运算符在1上进行评估,并具有比函数应用更高的优先级。这与Haskell通常的工作方式相反。已经对(-1)进行了特殊考虑,被解释为(negate 1)。这可能会引起一些问题,因为它是一个特例 - 在例子中尝试柯里化-不起作用,因为它实际上不是-, 而是negate。

可以想象,如果为-创造了一个更广泛的特例,会导致更多经验丰富的Haskell程序员无法预料的行为,因此语言设计者认为这并不值得。


2
但是,由于减号是一个一元运算符,当没有在后面加上空格时,它应该被解释为一个一元运算符,因此不应该与其后的数字分开。 - user109964
但将一元运算符作为另一个函数的参数传递是完全有效的。如果你认为这违背了语言设计哲学,那是你的权利,不过我建议在你了解它们如何协同工作之前先保留判断。 - psr
1
我认为人们并不认为需要使用括号来表示负数是理想的,但考虑到语言语法的其他部分,这是一个非常难以解决的问题,因为修复它可能会破坏其他有用的功能。 - psr
2
“但是,由于减号是一元运算符” - 不是的。它是二元减法,而且该语言有一个特殊规则,规定部分 (-x) 不像其他任何运算符那样被解释为 (\y -> y - x),而是作为 (negate x) - Ingo
1
@psr 实际上,解析器将表达式soma - 1 2解释为(-) soma (1 2)。这就解释了关于函数不是Num的实例的投诉。 - Ingo
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接