[英]Java Generics Inferred Types
好的,所以我在java中实现状态monad。 但是,我似乎无法让泛型工作正常。 我有下面的代码,我正在努力避免指出的情况。
public interface Monad<M, A>
{
<B, R extends Monad<M, B>> R bind(Function<? super A, R> p_function);
}
public class State<S, A> implements Monad<State<S, ?>, A>
{
private Function<S, Pair<S, A>> m_function;
public State(Function<S, Pair<S, A>> p_function)
{
m_function = p_function;
}
public final Pair<S, A> run(S p_state)
{
return m_function.apply(p_state);
}
@Override
public <B, R extends Monad<State<S, ?>, B>> R bind(
final Function<? super A, R> p_function)
{
// I want to avoid the cast to R here
return (R) new State<S, B>((S state) -> {
Pair<S, A> run = run(state);
// And this cast, but they seem related
State<S, B> applied = (State<S, B>) p_function.apply(run.second());
return applied.run(run.first());
});
}
}
注意:我知道如果我能够bind
的签名
<B> Monad<M, B> bind(Function<? super A, ? extends Monad<M, B>> p_function);
演员阵容可以避免。 但是,这会导致以下方法中的编译错误
public static <A, B, C, M, MB extends Monad<M, B>, MC extends Monad<M, C>>
Function<A, MC> compose(
Function<? super A, MB> p_first, Function<? super B, MC> p_second)
{
// have to use an anonymous class here, because using a closure causes a
// runtime error with the beta version of JDK 8
return new Function<A, MC>() {
@Override
public MC apply(A arg) {
MB monadOfB = p_first.apply(arg);
return monadOfB.<C> bind(p_second); // <-- type error here
}
};
}
现在,我也尝试以类似的方式改变compose
的签名。 即,而不是MB extends Monad<M, B>
我使用Monad<M, B>
其中使用MB并且类似地使用MC。 这使得compose
方法编译。 然而, compose
的调用者无法正确推断返回类型
Function<String, State<Integer, String>> left = ...;
Function<String, State<Integer, String>> right = ...;
Function<String, State<Integer, String>> composed = Monad.compose(left, right);
如果没有在方法调用上指定类型,则不起作用,而在此之前。
如何使所有这些仿制药一起很好地发挥作用?
为了使您的示例正常工作,您需要以类似于以下方式定义类:
class State<S, B> extends Monad<State<S, ?>, B> {}
class Monad<T, U> {}
R
是Monad<State<S, ?>, B>
的子类,sb也是Monad<State<S, ?>, B>
的子类,但没有理由它也是R
这就像写作:
Number n = 123.5d;
Integer i = n; //does not compile: cast required
Integer j = (Integer) n; //throws an exception
编辑
我不熟悉你想要实现的目标,这个简化可能无法实现你的目标,但它会编译(我已经删除了lambdas,因为我目前没有安装jdk8编译器):
public class Test1 {
public static <A, B, C, M> Function<A, Monad<M, C>> compose(final Function<? super A, Monad<M, B>> p_first,
final Function<? super B, Monad<M, C>> p_second) {
// have to use an anonymous class here, because using a closure causes a runtime error
// with the beta version of JDK 8
return new Function<A, Monad<M, C>>() {
@Override
public Monad<M, C> apply(A arg) {
Monad<M, B> monadOfB = p_first.apply(arg);
return monadOfB.bind(p_second); // <-- type error here
}
};
}
}
interface Monad<M, A> {
<B> Monad<M, B> bind(Function<? super A, Monad<M, B>> p_function);
}
class State<S, A> implements Monad<State<S, ?>, A> {
private Function<S, Pair<S, A>> m_function;
public State(Function<S, Pair<S, A>> p_function) {
m_function = p_function;
}
public final Pair<S, A> run(S p_state) {
return m_function.apply(p_state);
}
@Override
public <B> Monad<State<S, ?>, B> bind(final Function<? super A, Monad<State<S, ?>, B>> p_function) {
// I want to avoid the cast to R here
return new State<S, B>(new Function<S, Pair<S, B>>() {
public Pair<S, B> apply(S state) {
Pair<S, A> run = run(state);
// And this cast, but they seem related
State<S, B> applied = (State<S, B>) p_function.apply(run.second());
return applied.run(run.first());
}
});
}
}
这是一个通过Java 7类型检查器的版本:
class State<S, A> implements Monad<State<S, ?>, A> {
private Function<S, Pair<S, A>> m_function;
public State(Function<S, Pair<S, A>> p_function)
{
m_function = p_function;
}
public final Pair<S, A> run(S p_state)
{
return m_function.apply(p_state);
}
@Override
public <B> Monad<State<S, ?>, B> bind(
final Function<? super A, ? extends Monad<State<S, ?>, B>> p_function) {
return new State<S, B>(
new Function<S, Pair<S,B>>() {
public Pair<S,B> apply(S state) {
Pair<S, A> run = run(state);
// And this cast, but they seem related
State<S, B> applied = (State<S, B>) p_function.apply(run.second());
return applied.run(run.first());
}
});
}
public static <A, B, C, M>
Function<A, Monad<M,C>> compose(
final Function<? super A, ? extends Monad<M,B>> p_first,
final Function<? super B, ? extends Monad<M,C>> p_second) {
return new Function<A, Monad<M,C>>() {
@Override
public Monad<M,C> apply(A arg) {
Monad<M,B> monadOfB = p_first.apply(arg);
return monadOfB.<C>bind(p_second);
}
};
}
}
您的原始代码的问题是您想为R
选择一个特定的实例,但您的签名允许调用者选择它。 签名<B, R extends Monad<State<S, ?>, B>> R bind(final Function<? super A, R> p_function)
让调用者选择Monad<State<S, ?>,B>
的任意子类型Monad<State<S, ?>,B>
并要求bind
返回它。 但是你的bind
实现没有这样做:它决定总是返回你选择的R
的特定子类型。 所以你的签名是有前途的,但是你的实现正在做另一件事。
我的修复删除了这个承诺。 修改后的签名只允许返回一些子类型 - 在这种情况下意味着我可以完全免除泛型变量并且只需替换它,而不是允许调用者选择特定的Monad<State<S,?>,B>
子类型。直接在签名中的上限类型。
类似的问题影响了compose
方法 - 允许调用者选择MB
和MC
类型,但是期望能够在实现中为MB
和MC
生成您自己选择的子类型。 我以类似的方式解决了这个问题。
(我是jacobm的答案,我只想详细说明根本问题。)
问题是在Java中, GenericClass<S>
和GenericClass<T>
之间没有特定的关系:我的意思是,两者都是GenericType<?>
子类型,但是GenericInterface<T>
没有办法可以引用你的类型通过取getClass()
并用T
代替S
。
在Haskell中, Monad
类型类的定义如下所示:
class Monad m where
(>>=) :: m a -> (a -> m b) -> m b
return :: a -> m a
注意,它通过使用ma
和mb
来定义m
,意思是“相同的参数化类型m
,具有(可能)不同的类型参数a
和b
”。 在Java中,你不能创建的超类型m
(即一个接口m
)表达这样的事情,因为虽然超可以参考自己任意类型的参数(因为它可以通过名称来指代自己,就像它可以使用任何其他泛型类型一样,并且可以引用具有任何单个类型参数的任意子类型(即它自己的),它无法使用任意类型参数引用任意子类型。 它不像Haskell类型类定义那样位于类型系统的“外部”。
这意味着没有真正的方法来定义通用Monad
接口,其实现是通用的monadic类型。
告诉我,如果这种简化仍然代表您的问题:
以下编译:
public class TestClass {
public interface Monad {
<R extends Monad> R bind();
}
public class State implements Monad {
@Override
public <R extends Monad> R bind() {
return (R) new State(); // [1]
}
}
public <M extends Monad> M apply() {
M subMonad = null;
return subMonad.bind();
}
}
您想从[1]中删除演员表。 如果你这样做:
public class TestClass {
public interface Monad {
Monad bind();
}
public class State implements Monad {
@Override
public Monad bind() {
return new State();
}
}
public <M extends Monad> M apply() {
M subMonad = null;
return subMonad.bind(); // [2]
}
}
然后[2]不编译。 这总结了吗? 如果是这样, apply()
方法可以简单地返回一个Monad
吗?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.