构建 monad 时 Java 泛型的问题
Problems with Java Generics while building a monad
我正在研究 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
方法的 return 类型是原始的:
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
的第一次调用应该 return 包装在 monad 中的转换对象,或者如果条件为真,则应该是包装在 monad 中的原始对象错误的。但是由于您将 null
作为两种情况的条件传递,因此对 apply
的任何后续调用都会导致达到第二个 return
,因此总是 returning 结果第一次调用 apply
.
事实上,不可能 return 原始对象或转换后的对象(无论如何都不是有用且类型安全的方式)。要以类型安全的方式执行此操作,您需要一个 Either<If<T>, If<R>>
(假设存在这样的类型)。但是要从 Either
中提取值,您仍然需要一个 if 语句,这违背了 If<T>
class.
的目的
显然,这只是练习编写 monad 的练习。既然如此,我建议你选择另一个monad来实现,比如Either
。我也建议你先看看这个post。
我正在研究 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
方法的 return 类型是原始的:
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
的第一次调用应该 return 包装在 monad 中的转换对象,或者如果条件为真,则应该是包装在 monad 中的原始对象错误的。但是由于您将 null
作为两种情况的条件传递,因此对 apply
的任何后续调用都会导致达到第二个 return
,因此总是 returning 结果第一次调用 apply
.
事实上,不可能 return 原始对象或转换后的对象(无论如何都不是有用且类型安全的方式)。要以类型安全的方式执行此操作,您需要一个 Either<If<T>, If<R>>
(假设存在这样的类型)。但是要从 Either
中提取值,您仍然需要一个 if 语句,这违背了 If<T>
class.
显然,这只是练习编写 monad 的练习。既然如此,我建议你选择另一个monad来实现,比如Either
。我也建议你先看看这个post。