如何用无点风格组合(:)构造器实现列表双元素添加函数?
仅用组合子(.)实现无点风格的
addTwoElems 正确的无点实现
addTwoElems :: a -> a -> [a] -> [a] addTwoElems = (.) . (:)
推导步骤与逻辑
我们从最基础的有参数定义出发,逐步拆解成仅用(.)和(:)的无点形式:
从原始定义转换为函数组合形式
原始的直观实现是:addTwoElems x y xs = x : y : xs右侧的
x : y : xs本质是嵌套的函数应用——先把y和xs传给(:)得到y:xs,再把x和这个结果传给(:)。用函数组合的写法可以改写为:addTwoElems x y = (:) x . (:) y这里
(:) x是一个固定了第一个参数的(:)(类型为[a] -> [a]),(:) y同理,两者的组合就是先执行y:xs再执行x:(...)的逻辑。移除参数
x,升级为高阶组合
现在我们需要把x也从参数列表中去掉。观察(:) x . (:) y,它等价于(.) ((:) x) ((:) y)——也就是把(:) x传给组合子(.),再把(:) y传给这个结果。这里的关键是把
(.)本身当成高阶函数来处理:(.) ((:) x)可以看作是先对x应用(:)得到(:) x,再把这个函数传给(.)。用组合子的写法,这个逻辑就是((.) . (:)) x——(.) . (:)的本质是\x -> (.) ((:) x),即接受一个元素x,返回一个“等待另一个函数来组合(:) x”的函数。最终移除所有参数
代入后,addTwoElems x y = ((.) . (:)) x y,此时x和y都是可以被柯里化隐式处理的参数,直接去掉后就得到了无点风格的最终实现:addTwoElems = (.) . (:)
背后的核心逻辑
- 柯里化的层级组合:Haskell函数默认都是柯里化的,
(:)是接受两个参数的柯里化函数,(.)是二元函数组合子。(.) . (:)本质是嵌套的高阶组合:先通过(:)把第一个元素x转换成一个列表拼接函数,再通过外层的(.),让这个函数能和第二个元素生成的拼接函数组合,最终得到一个能接受列表并完成两次拼接的函数。 - 类型匹配验证:
(.) . (:)的类型推导完全贴合addTwoElems的需求:(:)的类型是a -> [a] -> [a](.)的类型是(b -> c) -> (a -> b) -> a -> c- 组合后
(.) . (:)的类型为a -> a -> [a] -> [a],和目标函数的类型完全一致。
内容的提问来源于stack exchange,提问作者AlexSchell
相关产品推荐
相关产品推荐

