わかりましたので、状態モナドを Java で実装しています。ただし、ジェネリックを正しく機能させることができないようです。以下のコードがあり、示されているケースを回避しようとしています。
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
注: to
の署名を変更すると
<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>
つまり、MB が使用された場所で使用したのではなく、Monad<M, B>
MC も同様です。これにより、compose
メソッドがコンパイルされます。ただし、戻り値の型はcompose
ieの呼び出し元によって正しく推測できませんでした。
Function<String, State<Integer, String>> left = ...;
Function<String, State<Integer, String>> right = ...;
Function<String, State<Integer, String>> composed = Monad.compose(left, right);
メソッド呼び出しで型を指定しないと動作しませんが、以前は動作していました。
これらすべてのジェネリックをうまく連携させるにはどうすればよいですか?