Haskell是否禁止在单个函数定义中混用无点式和非无点式子句?
为什么这个Haskell mergeLists函数会报错?
首先直接说结论:你遇到的错误不是因为混用无点式和非无点式子句,而是因为函数的各个定义子句,显式写出的参数数量不一致。
先看你最初的错误代码:
mergeLists :: Ord a => [a] -> [a] -> [a] mergeLists [] = id mergeLists l [] = l mergeLists (x:xs) (y:ys) = if y < x then y : mergeLists (x:xs) ys else x : mergeLists xs (y:ys)
对应的错误信息很明确:
MergeLists.hs:3:1: error: Equations for ‘mergeLists’ have different numbers of arguments MergeLists.hs:3:1-18 MergeLists.hs:4:1-19 | 3 | mergeLists [] = id | ^^^^^^^^^^^^^^^^^^...
问题根源:子句参数数量不统一
Haskell的函数定义要求,同一个函数的所有模式匹配子句,显式声明的参数个数必须完全一致。
从类型签名能看出来,mergeLists是一个柯里化的函数,本质是[a] -> ([a] -> [a])——接受第一个列表后,返回一个接受第二个列表的函数。
- 你的第一个子句
mergeLists [] = id:只显式写了1个参数([]),右边的id正好是[a] -> [a]类型,和mergeLists []的类型匹配。 - 但后面的子句
mergeLists l [] = l和mergeLists (x:xs) (y:ys) = ...都显式写了2个参数,这就和第一个子句的参数数量产生了冲突,Haskell编译器会认为你在定义不同的函数,所以抛出错误。
为什么修改后就正常了?
你把第一个子句改成mergeLists [] l = l后,这个子句也显式写了2个参数,和其他子句的参数数量统一了。其实这个写法和mergeLists [] = id是完全等价的——mergeLists [] l = l可以简化成mergeLists [] = \l -> l,也就是mergeLists [] = id,只是显式写出了第二个参数,符合编译器对参数数量一致性的要求。
那能不能混用无点式和非无点式?
当然可以!只要保证所有子句的显式参数数量一致就行。比如下面这个写法也是合法的(虽然可读性很差):
mergeLists :: Ord a => [a] -> [a] -> [a] mergeLists [] = id mergeLists (x:xs) = \ys -> case ys of [] -> x:xs (y:ys') -> if y < x then y : mergeLists (x:xs) ys' else x : mergeLists xs ys'
这里第一个子句用了无点式(1个参数),第二个子句也用了无点式(1个参数),参数数量一致,编译器完全接受。
总结
- Haskell不禁止混用无点式和非无点式子句,核心要求是所有子句的显式参数数量必须相同。
- 你遇到的错误纯粹是因为子句之间的参数个数不统一,和无点式本身无关。
内容的提问来源于stack exchange,提问作者fghzxm
相关产品推荐
相关产品推荐

