当需要输入来构建管道时,我该如何组合函数?

4

我正在尝试使用Ramda库在javascript中学习一些函数式编程,并且我经常遇到这样的情况,即我组合了一堆函数,然后必须将输入传递两次才能得到结果。下面是一个工作示例代码:

const search = R.invoker(1, 'search');
const substring = R.invoker(2, 'substring');
const lSplit = (pat, s) => R.compose(substring(0), search(pat))(s)(s);
lSplit(/ /, 'foo bar');
lSplit接受一个正则表达式和一个字符串,定位字符串中第一个匹配项,并返回匹配项左侧的所有内容。最后一行的结果为'foo'。需要两次向合成函数传递s:第一次是为了找到模式并构建子字符串函数,第二次是在字符串上运行合成函数。代码可以工作,但(s)(s)看起来不太优雅。
我编写了一个名为twice的函数,可以使事情变得简洁一些,但不能真正解决这种不优雅的问题:
const search = R.invoker(1, 'search');
const substring = R.invoker(2, 'substring');
const twice = f => d => f(d)(d);
const lSplit = pat => twice(R.compose(substring(0), search(pat)));

lSplit(/ /)('foo bar');

有没有更简洁优雅的方式来处理这种情况:在将数据馈送到管道之前,需要使用数据构建管道?
1个回答

3
你的组合看起来很混乱,这是因为你正在将二元函数 search 与三元函数 substring 组合在一起。更糟糕的是,"piped" 参数出现在三元函数的中间位置。
               _ search(/ /, s)
              /
substring(0, /, s)

不必担心函数式编程中的"point free",只需编写能最好表达函数意义的函数即可。

const lSplit = (pat, s) => substring(0, search(pat,s), s);

虽然不是很聪明,但易于阅读。我的建议是让已完成的事情就这样吧。


谢谢!我想我还在努力弄清楚编写函数式代码的“正确”方式是什么(实际上并没有这样的事情)。而且我有点困扰于点无关的写法。你的方法更易读。 - ctcutler
1
同意。Ramda有一些聪明的函数,比如useWithconverge,而Sanctuary则公开了其他一些函数,例如meldS组合器。这些有时非常有用且易读,但太过频繁地使用会降低可读性,因此应该避免使用。 - Scott Sauyet

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