如何在Haskell中实现f(g x)(h x)点自由?

How to implement f (g x) (h x) point-freely in Haskell?

this answer学习如何在Haskell中以毫无意义的方式实现函数\x y z -> f x (g y z),其中fg是函数。我的问题是

How to write the function \x -> f (g x) (h x) in a pointfree manner in Haskell? Here f g h are functions for which f (g x) (h x) is defined.

我目前的想法是这样的。

uncurry f (mapTuple ($ x) (g, h))

但几次尝试表明这是错误的;甚至 map ($ x) [g, h] 部分也很可疑:如果 gh 的范围不同怎么办?

此外,可读性在这里不是太大的问题。

真诚感谢任何帮助。

melpomene 所建议,\x -> f (g x) (h x) 等同于 liftM2 f g h

当您对如何将 Haskell 代码转换为 pointfree Haskell 代码有疑问时,您可以尝试 Pointfree.io.

这是一个很好的工具,它经常可以告诉你什么时候不要使用 pointfree 代码,因为它有时会变得完全不可读:-)

arrow 版本为

uncurry f . (g &&& h)

(g &&& h) >>> uncurry f

如图:

        g ────
       ╱          ╲
──── &&&      >>>  uncurry f ───
       ╲          ╱
        h ──── 

应用式

f <$> g <*> h

Control.Compose

join ((g ~> h ~> id) f)

Data.Function.Meld

join (f $* g $$ h *$ id)

Data.Function.Tacit

lurryA @N1 (f <$> (g <$> _1) <*> (h <$> _1))
lurryA @N4 (_1 <*> (_2 <*> _4) <*> (_3 <*> _4)) f g h

本帖仅用于收集整理评论中的答案。 根据@PetrPudlák评论中link中的抽象-消除过程,我们也可以写成

S (S (K f) (S (K g) I)) (S (K h) I),

或者,减少 eta 后,

S (S (K f) g) h,

其中

S x y z = x z (y z)
K x y = x

特别是在 Haskell 中,感谢@melpomene 指出这一点,S 的角色由 ap 扮演,而 K 的角色由 const。因此我们可以写

ap (ap (const f) g) h

其实我们还可以进一步减少:

ap (const f) g = f . g

所以我们的函数可以写成:

ap (f . g) h

如果翻译成Applicative风格,我们得到:

f <$> g <*> h

那么这个系统化的方法就可以应用到所有的lambda项上,给出point-free风格。 :)