我正在玩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
.我也建议你先看看这篇文章。