这是一个复杂但有希望有趣的问题,来自那些做了太多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
的{{1}}等于{{ 1}}已应用于(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>
和interface Group<E> {
E plus(E,E);
}
:
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
和g
。在具体示例中,我们希望E
代表R
和g
。
现在,上面Group<Integer>.plus(Integer,Integer)
的实现不可行,因为对Group<Fraction>.plus(Fraction,Fraction)
的两次调用之间的唯一区别是泛型类型,它被删除。所以,我会通过将域和范围添加为对象来稍微修改它:
checkCommutesWith
那么接口(g.ap
)应该是什么样的?如果这是C ++,我会写相当于
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); }
}
但是AFAICT Java没有等效的模板模板参数。那就是我被困住的地方。
请注意,我不希望将Group包含为??
签名的一部分,因为我希望能够将此代码与其他结构一起使用。我认为通用定义应该是可能的(对于“应该”的某些定义:))。
更新/澄清问题的关键在于集合之间的映射的定义属性是它们与eq()通信。组同态的定义属性是它们与plus()通信。环同态的定义属性是它们与times()通勤。我正在尝试定义一个通用的commutesWith函数来捕获这个想法,我正在寻找正确的抽象来封装eq,plus和times(以及其他结构)。
答案 0 :(得分:1)
我不确定它对您的目的是否足够,但您可以检查JScience
库中定义的类型结构。特别是,org.jscience.mathematics.structure
中指定的接口可能代表一个有用的起点。
答案 1 :(得分:1)
我担心没有未经检查的强制转换,Java类型系统不够强大。 但是,它们的影响可以最小化。
考虑以Category-theoretical术语定义此内容。这通常足以表达所有事物,而群体同态是类别对象之间态射的具体案例。
有关以下代码的说明:
我将你的checkCommutesWith
加入morphismTester
关系。
2. eq
现在是CategoryObject
的属性,而不仅仅是参数。
3. castToConcreteObject
的{{1}}用于进行未经检查的演员表。在我们的示例中,如果仅使用Category
GroupsCategory
并且GroupObject
没有不同的实现,则这是安全的。
CategoryObject<GroupsCategory, E>
或许,要检查更多属性,您需要为每个属性定义一个类别。然后可能存在扩展其他几个类别的类别,这正是描述它们的对象的属性和它们之间的态射的原因。
答案 2 :(得分:1)