これは複雑ですが、Haskell と C++ テンプレートのメタプログラミングをやりすぎた人からの興味深い質問です。我慢してください
関数の特定の代数的プロパティをチェックするための一般的な Java コードを書いていますが、それらのいくつかに適切な型を考え出すのに苦労しています。
機能する例として、関数が交換可能であることを確認する関数を次に示します。
<E, R>
boolean checkCommutative( Binary<E,E,R> f
, Binary<R,R,Boolean> eq
, E a, E b)
{
return eq.ap(f.ap(a,b), f.ap(b, a));
}
この関数f
は次E
のように表示されます。_R
eq
R
a
b
E
f
(a,b)
f
(b,a)
次に、次のようにして、特定の関数C.plus(Integer,Integer)
が交換可能であることをテストできます。
class Plus implements Binary<Integer, Integer, Integer> {
Integer ap(Integer a, Integer b) { return C.plus(a,b); }
}
class Eq implements Binary<Integer, Integer, Boolean> {
Boolean ap(Integer a, Integer b) { return a.equals(b); }
}
checkCommutative(new Plus(), new Eq(), rand(), rand());
そして、すべてが順調です。
今、私はもっと複雑なものを実装したいと思っています。Group<E>
plus メソッドを持つジェネリック インターフェイスがあるとします。
interface Group<E> {
E plus(E,E);
}
と の 2 つの実装があるTheIntegers
としTheRationals
ます。
class TheIntegers implements Group<Integer> { ... }
class TheRationals implements Group<Fraction> { ... }
F
ここで、整数から有理数への一般的な関数が のg
ような関数と交換するという考えを捉えられるようにしたいと考えていGroup.plus
ます。最初のカットとして、次のようなものを書きたいと思います。
<E, R>
booleanCheckCommutesWith( Unary<E,R> f
, ?? g
, Binary<R,R,Boolean> eq
, E a, E b)
{
return eq.ap(f.ap(g.ap(a,b)), g.ap(f.ap(a), f.ap(b));
}
class F implements Unary<TheIntegers, TheRationals> {
Fraction ap (Integer x) { ... }
}
checkCommutesWith(new F(), new Plus(), new Eq(), rand(), rand());
ここでの質問は、型は何であるべきかというg
ことです。問題は、 が と の2g
つの異なるタイプに適用されることです。具体的な例では、 と の両方を表現したいと考えています。E
R
g
Group<Integer>.plus(Integer,Integer)
Group<Fraction>.plus(Fraction,Fraction)
checkCommutesWith
2 つの呼び出しの唯一の違いg.ap
は消去されるジェネリック型であるため、上記の実装は機能しない可能性があります。そこで、ドメインと範囲をオブジェクトとして追加して、少し変更します。
boolean checkCommutesWith( Unary<DE,RE> f
, ?? g
, Binary<RE,RE,Boolean> eq
, S domain, S range
, E x, E y)
{
return eq.ap( f.ap(g.ap(domain, x, y)),
, g.ap(range, f.ap(x), f.ap(y))
);
}
class Plus implements ??
{
<E, G extends Group<E>>
E ap (G gp, E x, E y) { return gp.plus(x,y); }
}
??
では、インターフェース ( ) はどのように見えるべきでしょうか? これが C++ の場合、次のように記述します。
interface ?? <T> {
<E, S extends T<E>>
E ap(S, E, E);
}
しかし、AFAICT Java には template-template パラメーターに相当するものはありません。それが私が立ち往生しているところです。
checkCommutesWith
このコードを他の構造でも使用できるようにしたいので、 Group を の署名の一部として含めたくないことに注意してください。一般的な定義が可能であるべきだと思います(「すべき」の定義について:))。
更新/明確化ここでの重要な点は、セット間のマップの定義プロパティは、それらが eq() で交換されるということです。群準同型の特徴は、それらが plus() で交換できることです。環準同型の特徴的な性質は、それらが times() で通勤することです。私は、この考えを捉える一般的な commutesWith 関数を定義しようとしています。また、eq、plus、および times (およびその他の構造も) をカプセル化するための適切な抽象化を探しています。