Haskell中是否总能用<$>实现无参数(point-free)函数定义?
核心问题解答
是的,任何含N个变量的纯函数式数学表达式,都能通过柯里化、函子操作(<$>/<*>)或函数组合转化为无显式参数的形式。这本质上是因为Haskell的函数默认是柯里化的——多参数函数本质是返回函数的一元函数,再结合函子对函数的操作能力,就能把所有参数逐步“消去”。
拆解第4步的推导过程
从你给出的步骤一步步倒推,就能搞清楚最后一步的来龙去脉:
原始版本:
doThing x y z = (x + y) * z消去
z:利用柯里化特性,(x+y)*z等价于((x+y) *) z,因此可以省略最后一个参数,得到:doThing x y = (x + y) *消去
y:这里用到了函子运算符<$>(即fmap)。对于函数类型的函子,fmap f g等价于\x -> f (g x)(函数组合的变体)。(x +)是接收y返回x+y的函数,(*)是二元函数,(*) <$> (x +)的作用是把(x +)的输出作为(*)的第一个参数,最终得到接收z的函数:doThing x = (*) <$> (x +)消去
x:现在要把x也去掉。首先,(x +)其实是(+) x——也就是二元函数(+)接收x后的部分应用。而((*) <$>)是一个函数:它接收一个一元函数h,返回(*) <$> h。所以
doThing x = ((*) <$>) ((+) x),而根据函数函子的fmap定义,f <$> g等价于\x -> f (g x)(即函数组合f . g),因此((*) <$>) <$> (+)就等价于((*) <$>) . (+),也就是把(+)的输出(即(x +))传给((*) <$>),最终得到无参数的版本:doThing = ((*) <$>) <$> (+)
复杂表达式的无点转化示例
举个更复杂的例子,比如f x y z = x² + y*z - 3,也能转化为无显式参数的形式:
- 消去
z:f x y = (-3) <$> ((+) (x²) <$> (*) y) - 消去
y:f x = ((-) <$>) <$> ((+) (x²) <$>) . (*) - 消去
x:f = ((-) <$>) . (. (*)) . ((<$>) . (+)) . (^2)
虽然这个写法可读性极差,但理论上完全可行。
实际编程建议
这种无点(point-free)风格在实际开发中只适合简化简单逻辑,强行把所有参数都消去会严重降低代码可读性,属于“炫技大于实用”的写法,日常编程不建议这么做。
内容的提问来源于stack exchange,提问作者FuzzyCat444

