Haskell函数组合运算符使用报错问题咨询
让我们逐个拆解你遇到的这几个表达式问题,核心在于Haskell的运算符优先级和语法解析规则:
1. 错误根源:-被解析为减法而非负号
先看你遇到的第一个错误案例:
(negate.abs) -7
Haskell会把这个表达式解析为:
(negate . abs) - 7
也就是说,它把-当作了减法运算符,而不是负号来处理。这就要求函数(negate . abs)必须属于Num类型(因为减法只能在数值之间进行),但函数显然不是数值类型,所以编译器抛出了Num (c -> c)的错误——它试图把函数当作数值来做减法,这当然不合法。
2. 逐个分析你的表达式
表达式1:(negate.abs) -7
如上面所说,被解析为函数减7,完全不符合你的意图。如果你想让-7作为参数传入组合后的函数,需要明确告诉编译器-7是一个负数,而不是减法操作。有两种正确写法:
(negate . abs) (-7) -- 用括号把负号参数括起来 (negate . abs) $ -7 -- 用$运算符分隔函数和参数
表达式2:negate (abs -7)
其实这个表达式应该是能正常运行的!因为函数应用优先级最高,abs -7会被Haskell正确解析为abs (-7),所以整个表达式等价于negate (abs (-7)),结果是-7。如果运行时出错,可能是输入时的格式问题(比如少了空格),可以再检查一下。
表达式3:negate.abs -7
这个同样犯了和第一个表达式一样的错误:.的优先级是infixr 9(非常高),-的优先级是infixl 6,所以这个表达式会被解析为:
(negate . abs) - 7
同样是函数减7,导致类型错误。正确的写法需要把参数明确标记为负数:
negate . abs $ -7 -- 用$分隔 negate (abs (-7)) -- 显式括号
表达式4:negate.abs $ 7
这个表达式应该是可以正常运行的!$是infixr 0(优先级最低),所以它会把左边的negate . abs作为函数,右边的7作为参数,等价于(negate . abs) 7,结果是-7。如果运行出错,大概率是输入时的格式问题——比如negate.abs之间没有空格?Haskell中.是中缀运算符,两边需要有空格,正确写法是negate . abs $ 7,而不是negate.abs $ 7(后者会被解析为一个名为negate.abs的变量,显然不存在)。
总结关键规则
- 函数应用优先级最高:任何函数后面紧跟的表达式都会被当作它的参数,所以
abs -7会被解析为abs (-7),而不是abs - 7。 -的双重身份:当-前面有表达式时,它是减法运算符;当它单独出现在一个数值前时,才是负号。如果要把负数作为参数传给组合后的函数,必须用括号括起来,或者用$分隔。.和$的优先级:.优先级极高,$优先级极低,用$可以避免写多层括号,同时明确区分函数和参数。
内容的提问来源于stack exchange,提问作者SAN

