Java 函数式编程中具有两个值的 Monad Map

问题描述 投票:0回答:1

如果这是 FP 中的基本问题,请原谅我。让我们考虑可选单子。我知道我可以使用

map
根据函数将
Optional
转换为另一个
Optional
(如果可选值有值,将调用该函数)。但是如果我的函数有两个输入而不是一个怎么办?

例如:

var data = Optional.of(100);
var result = data.map(x -> x * 2); //all good!

但是呢:

int getData(Connection conn, int data) { ... }

var data = Optional.of(100);
var connection = getOptionalDataConnection();
var result = data.map(i -> getData(connection?, i));  //this does not work as the getData function only accepts non-optionals

我确信 FP 世界中有一个术语,我只是不熟悉它。但我的想法是我有一个地图函数,它接受“两个”输入,而不是一个。我想要一个助手/实用程序/...如果两个输入都在那里,它将调用我的函数。但如果其中任何一个是“空”,则应返回

Optional.empty()

这叫什么?Java 支持吗?

java functional-programming option-type monads
1个回答
0
投票

在我们深入研究这个问题之前,我的蜘蛛侠感官已经开始刺痛了。这个:

但是如果其中任何一个是“空”,则应返回Optional.empty()。

这是一个坏主意。如果你替换 50 个 NullPointerException 错误,这在客观上是鲁棒性和生产力的一个相当大的损失,这至少直接指出了问题所在并确保执行不会继续,用 10 个'呵呵,奇怪 - 这段代码......它......做了由于某种原因没有任何错误。这 10 个错误可能会产生非常严重的副作用(因为代码会继续),并且需要花费比这些 NPE 多 5 倍的时间来修复,因此您的处境会更糟,需要花费更多的时间来寻找错误。而这种随意的违约(“呃,什么也不做!”)正是你到达那个令人讨厌的地方的方式。 所以,你知道的——对SO的品味进行深入研究可能有点太过分了,但是,哦。不要做任何这样的事情。我不太确定这总体上是个好主意,但是

在java中

这不好。 注意:因为泛型和可选是不好的,所以我用

int

替换了

Integer
的所有使用,因为由于基元和泛型的限制,如果不这样做,这将无法正常工作。
部分申请

您正在寻找的答案是部分应用。

您当前拥有的是一个接受

Connection

Integer
并返回
Integer
的函数。您需要的是一个接受
Optional<Connection>
Integer
并返回
Optional<Integer>
的函数。具体来说,提供了
Optional<Connection>
,但 Integer 是输入。那么让我们这样做吧:
Optional<Connection> connection = getOptionalDataConnection();
Function<Integer, Optional<Integer>> f = i -> connection.map(c -> Optional.of(getData(c, i)));

有了这个功能,我们就可以轻松完成工作了:

Optional<Connection> connection = getOptionalDataConnection(); Function<Integer, Optional<Integer>> f = i -> connection.map(c -> Optional.of(getData(c, i))); Optional<Integer> data = Optional.of(100); var result = data.flatMap(i -> f.apply(i));

这是相当多的代码,对于我的敏感性来说,这里大部分都失去了真正的本质。但是,这就是 java 中的内容(具体来说,Optional 的 
flatMap

)。您可以编写实用程序方法,将选项转换为可平面映射的函数。

我们把它放在一起:

import java.util.function.*; import java.util.*; class Example { public static <U, V, R> Optional<R> compose( Optional<U> first, Optional<V> second, BiFunction<U, V, R> func) { Function<V, Optional<R>> f = v -> first.map(u -> func.apply(u, v)); return second.flatMap(v -> f.apply(v)); } public static String make(String a, Integer b) { return a + ", " + b; } public static void main(String[] args) { Optional<String> as = Optional.of("Hello"); Optional<Integer> bs = Optional.of(100); Optional<String> an = Optional.empty(); Optional<Integer> bn = Optional.empty(); BiFunction<String, Integer, String> func = Example::make; System.out.println(compose(as, bs, func)); System.out.println(compose(as, bn, func)); System.out.println(compose(an, bs, func)); System.out.println(compose(an, bn, func)); } }

与本例有些相关的相关术语是“柯里化”。将各种内容包装在可选中的更一般原则,我什至不确定它是否有名称。

© www.soinside.com 2019 - 2024. All rights reserved.