构建 monad 时的 Java 泛型问题



我正在玩Java代码以创建一个函数式风格的monad,但是我在使用泛型时感到震惊,如果我不转换我的对象,Java编译器会给我一个编译错误(尽管泛型可以解决这个问题!

这是用法:

//COMPILATION ERROR! It requires a cast to String
String message = If.of("Hi", s->s!=null).apply(s->s+" guys!").get();

允许:

这是我的单子:

import java.util.function.Function;
import java.util.function.Predicate;
public class If<T, R> {
private T t;
private Predicate predicate;
private If(T t, Predicate predicate) {
this.t = t;
this.predicate = predicate;
}
public static<T> If of(T t, Predicate predicate) {
return new If(t, predicate);
}
public If<R,R> apply(Function<T, R> function) {
if(predicate!=null && predicate.test(t)){
return new If<R, R>(function.apply(t), null);
}
return If.of(this.t, null);
}
public T get() {
return t;
}
}

直接的问题是of方法的返回类型是原始的:

public static<T> If of(T t, Predicate predicate) {

您可能需要它类似于:

public static<T> If<T, Something> of(T t, Predicate<T> predicate) {

我建议你不要真的想把R烘焙成If的类型。如果改为在方法上声明它,则可以灵活地将其apply为所需的任何类型:

public class If<T> {
// ...
public <R> If<R> apply(Function<T, R> function) {
if(predicate!=null && predicate.test(t)){
return new If<>(function.apply(t), null);
}
return If.of(this.t, null);
}
// ...
}

然后,您的of签名可以简单地:

public static<T> If<T> of(T t, Predicate<T> predicate) {

如果您希望 API 更灵活一些,请添加通配符:

public static<T> If<T> of(T t, Predicate<? super T> predicate) {

public <R> If<R> apply(Function<? super T, ? extends R> function) {

Andy Turner 的回答解释了为什么你当前的代码无法编译,但你的 monad 似乎有一个更根本的问题——它不是很有用。

根据您的说法,如果条件为真,则第一次调用apply应返回包装在 monad 中的转换对象,如果条件为 false,则返回包装在 monad 中的原始对象。但是,由于您将null作为这两种情况的条件传递,因此任何后续对apply的调用都将导致到达第二个return,因此始终返回第一次调用apply的结果。

事实上,不可能返回原始对象或转换后的对象(无论如何,不是以有用且类型安全的方式(。若要以类型安全的方式执行此操作,您需要一个Either<If<T>, If<R>>(假设存在此类类型(。但是要从Either中提取值,您仍然需要一个 if 语句,这违背了If<T>类的目的。

显然,这只是练习写单子的练习。在这种情况下,我建议您选择另一个 monad 来实现,例如Either.我也建议你先看看这篇文章。

最新更新