使用谓词和两个函数映射集合

时间:2017-07-08 14:45:55

标签: functional-programming language-agnostic mapping ternary-operator

在尝试以函数样式编写代码时,我经常会遇到这样的场景:我想使用两个函数将一个集合或流映射到另一个集合:一个函数应用于传递给定谓词的元素,另一个函数应用于元素失败。这两个函数都会生成一个公共输出,应该收集这些输出以供进一步处理。

这是Java中一个人为的例子。

Stream.of("foo", "bar", "baz", "qux")
      .map(it -> it.startsWith("ba") ? it.toUpperCase() : new StringBuilder(it).reverse())
      .forEach(System.out::println);

和Groovy中的相同示例。

["foo", "bar", "baz", "qux"]
      .collect{ it.startsWith("ba") ? it.toUpperCase() : it.reverse() }
      .each{ println(it) }

我的问题是关于用于实现此映射的条件(三元)语句。是否存在实现这种映射的功能习惯用法而不诉诸分支逻辑?

1 个答案:

答案 0 :(得分:1)

您始终可以使用其他函数对表达式进行抽象。由于您标记了语言无关的问题,因此我使用Javascript对您的示例进行编码,可在您喜欢的浏览器中执行 - 我希望这没关系:



// select :: (a -> Boolean, a -> b, a -> b) -> a -> b
const select = (p, f, g) => x => p(x) ? f(x) : g(x);

// mapSelect :: (a -> Boolean, a -> b, a -> b) -> [a] -> [b]
const mapSelect = (p, f, g) => xs => xs.map(select(p, f, g));

const reverse = s => s.split("").reverse().join("");
const toUpperCase = s => s.toUpperCase();
const startsWith = s => t => t.indexOf(s) === 0

const xs = ["foo", "bar", "baz", "qux"];

console.log(
  mapSelect(startsWith("ba"), toUpperCase, reverse) (xs)
);




显然,mapSelect并没有将您从条件运算符中拯救出来。它只是另一层抽象。由于它不像map那么常见,所以尤其会增加同事的认知负担而不会增加太多。

结论:我会坚持使用显式条件运算符,而不是伪装分支逻辑。