g(f(x)(y)) 的 point-free 版本

4
有没有一种方式可以用点无形式(Point-free form)表示以下内容:
g(f(x)(y))

就我所见,这不是一种常见的“组合器”,尽管可能有不同的表达方式? 我正在使用 Ramda 进行 Javascript 编程。


2
这是一个相当著名的 Blackbird combinatorλabcd . a(bcd)。Ori Drori 的答案提供了一个简单版本,而 customcommander 的评论则提供了一个不错的替代方案。 - Scott Sauyet
1
趣闻:在 Haskell 中,蓝鸟是“.”,如果你想将其作为参数传递给其他函数,则必须将其括在括号中,即“(.)”;因此,在 Haskell 中,黑鸟是“(.).(.)”,有时被称为“山雀运算符”,原因显而易见。 - Enlico
2个回答

3

我无法想到一种可读性良好的方式以点式形式创建此组合子。然而,自从引入了箭头函数到JS中后,创建可读性高的组合子变得非常容易。您还可以使用Ramda的R.curry对它们进行柯里化,而不是手动进行柯里化(f => g => x => y => g(f(x)(y))):

const { curry, on, identity, multiply, add } = R

const combinator = curry((f, g, x, y) => g(f(x)(y)))

const square = n => n * n;

const squareAddition = combinator(add, square)

const result = squareAddition(1, 2)

console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.28.0/ramda.min.js" integrity="sha512-t0vPcE8ynwIFovsylwUuLPIbdhDj6fav2prN9fEu/VYBupsmrmk9x43Hvnt+Mgn2h5YPSJOk7PMo9zIeGedD1A==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>


1
pipe(f, g) 等价于调用 combinator(f, g) 的结果,而不是组合器本身,并且它不是柯里化的。 - Ori Drori
啊,好的。const C = curryN(2, compose(curry, pipe)); C(add)(negate)(40)(2); - customcommander
这很棒,@customcommander提供的答案和替代方案都很好。但我更喜欢一个不同的例子,因为addnegate彼此交换,所以这个例子并没有清楚地表明是add(negate(x))(negate(y))还是negate(add(x)(y))。也许combinator(add, square)会更好? - Scott Sauyet
1
好主意。更新为正方形。 - Ori Drori
1
很好的回答和讨论! - jramm
显示剩余4条评论

3
这是一个无参点语法的comp2函数 -

// comp : ('b -> 'result) -> ('a -> 'b) -> ('a -> 'result)
const comp = f => g =>
  x => f(g(x))

// comp2 : ('c -> 'result) -> ('a -> 'b -> 'c) -> ('a -> 'b -> 'result)
const comp2 =
  comp(comp)(comp)

// square : number -> number
const square = x =>
  x * x

// add : number -> number -> number
const add = x => y =>
  x + y
 
// addThenSquare : number -> number -> number 
const addThenSquare =
  comp2(square)(add)
  
console.log(addThenSquare(3)(2))
// 25 : number

当然,这种点无风格的写法非常有效,但也许对于你来说这个comp2更加适合 -

// comp2 : ('c -> 'd) -> ('a -> 'b -> 'c) -> ('a -> 'b -> 'd)
const comp2 = f => g =>
  a => b => f(g(a)(b))

如果您需要,这里有 comp3comp4comp5 -

// comp3 : ('d -> 'result) -> ('a -> 'b -> 'c -> 'd) -> ('a -> 'b -> 'c -> 'result)
const comp3 =
  comp(comp)(comp2)

// comp4 : ('e -> 'result) -> ('a -> 'b -> 'c -> 'd -> 'e) -> ('a -> 'b -> 'c -> 'd -> 'result)
const comp4 =
  comp(comp)(comp3)

// comp5 : ('f -> 'result) -> ('a -> 'b -> 'c -> 'd -> 'e -> 'f) -> ('a -> 'b -> 'c -> 'd -> 'e -> 'result)
const comp5 =
  comp(comp)(comp4)

1
考虑到 OP 如何在无点形式下表达 g(f(x,y)),我认为这个答案更正确,因为它至少以更基本的组合子 bluebird 为起点构建了 blackbird 组合子(正如在问题的评论中所指出的那样, blackbird 就是 OP 描述的组合子的名称),而 @Mulan 称之为 comp,因为它是函数复合的 bird。 - Enlico
2
这让我想起了好老的 comp(comp) (comp)。当我学到它时,我真的很兴奋。对称性不是很令人感到舒适吗? - user5536315

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接