Haskell函数组合点符号使用疑问:如何改写sum(map square [1..n])
Haskell函数组合(点符号)的错误原因与正确用法
先看你现有的正确代码:
平方函数:
square :: Integer -> Integer square x = x * x
用括号实现的求和平方函数:
sumsquares :: Integer -> Integer sumsquares n = sum (map square [1..n])
错误写法的问题分析
sum . map square [1..n]报错原因
函数组合运算符(.)的作用是组合两个函数,它的类型是(b -> c) -> (a -> b) -> a -> c——要求左右两边都是函数,且前一个函数的输出类型能匹配后一个的输入类型。
而map square [1..n]已经是一个具体的列表值(不是函数),sum是[Integer] -> Integer类型的函数,你试图把函数和值组合,完全不符合(.)的使用规则,所以报错。sum . square map [1..n]报错原因
这个写法的结构和类型完全混乱:square的参数需要是Integer类型,但你把map(一个函数)传给它,类型不匹配;同时[1..n]的位置也不对,整个表达式既不符合函数组合逻辑,也不符合函数调用规则,必然报错。
正确的点符号使用方式
函数组合的核心是组合函数而非值,所以需要把[1..n]转换成一个接受n作为参数的函数,再和其他函数组合。
无点风格(Point-free)写法
sumsquares :: Integer -> Integer sumsquares = sum . map square . enumFromTo 1
解释:
enumFromTo 1是一个Integer -> [Integer]类型的函数,作用是接受参数n,生成列表[1..n]map square是[Integer] -> [Integer]类型的函数,对列表每个元素平方sum是[Integer] -> Integer类型的函数,对列表求和
这三个函数的输入输出类型依次匹配,用(.)组合后,就得到了一个Integer -> Integer类型的函数,和sumsquares的类型完全一致。
保留参数的写法(结合$避免括号,注意这不是函数组合)
如果你想保留参数n,可以用函数应用运算符$来替代括号,写法是:
sumsquares :: Integer -> Integer sumsquares n = sum $ map square [1..n]
$的作用是降低右边表达式的优先级,让右边先执行,和括号写法等价,但这不属于函数组合的范畴,只是简化括号的技巧。
内容的提问来源于stack exchange,提问作者Alex Kay
相关产品推荐
相关产品推荐

