2012-10-26 29 views
2

这是从别人一个复杂的,但希望有趣的问题是谁在做太多Haskell和C++模板元编程。请跟我使Java功能的正确方法对象来封装通用功能

我写一些通用的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的定义的相等),如果对于任何aE类型的b,施加到(a,b)f等于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); 
} 

比方说,我有两种实现方式:TheIntegersTheRationals

class TheIntegers implements Group<Integer> { ... } 
class TheRationals implements Group<Fraction> { ... } 

现在,我希望能够捕捉到的想法,从整数到有理数的通用函数F通过与Group.plus类似的函数g来通勤。作为第一个切,我想写的东西是这样的:

<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应用于两种不同类型:ER。在具体的例子中,我们希望g代表Group<Integer>.plus(Integer,Integer)Group<Fraction>.plus(Fraction,Fraction)。现在

checkCommutesWith实施上述不可能工作,因为到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没有模板,模板参数相当。这就是我卡住的地方。

请注意,我不希望将组作为checkCommutesWith签名的一部分,因为我希望能够将此代码与其他结构一起使用。我认为一个通用的定义应该是可能的(对“应该”:)的一些定义)。这里

更新/澄清的问题的关键是,集之间的映射的定义特性是它们与通勤EQ()。群同态的定义属性是他们通过plus()。环同态的定义属性是他们通过times()。我试图定义一个通用的commutesWith函数来捕获这个想法,并且我正在寻找正确的抽象来封装eq,plus和times(以及其他结构)。

+0

策略模式 – rees

+0

“的问题是,克施加到两种不同类型: E和R“。如果是这样,问题在于你的设计,而不是java。 Java在不允许的情况下是正确的。你能举出更具体的例子吗? –

+0

@AlexeiKaigorodov:考虑函数plus()。如果我给它一个小组,以及来自该小组的两个元素,那么它应该给我一个该小组的一个元素。我应该能够将它应用到TheRationals中,以从一对理性到理性获得一个函数,并且让TheIntegers从一个整数到一个整数。 类似地,times(),当提供一个环时,以及该环的两个元素,应该为我提供该环的一个元素。因此,我试图封装的常见结构是一个函数形式> E ap(S,E,E),对于任意的T. – mdgeorge

回答

1

我不确定它是否足够满足您的需要,但您可以检查JScience库中定义的类型结构。特别是,在org.jscience.mathematics.structure中指定的接口可能是一个有用的起点。

+1

这实际上与我正在尝试实现的非常相似,但它不提供我在这里提到的特定功能。在该包中,简单地假定数学对象满足它们应该的属性,而我正在尝试编写一个单元测试框架。 – mdgeorge

1

我担心Java分类系统不够强大,如果没有未经检查的强制转换, 但是,它们的影响可以最小化。

请考虑在Category-theoretical条款中定义此项。这足以表达一切事物,并且这些组同态是类别对象之间态射的具体情况。

关于下面的代码的注意事项: 1.我将你的checkCommutesWith关联到morphismTester关系。 2. eq现在是CategoryObject的一个属性,而不仅仅是一个参数。 3. castToConcreteObject of Category用于进行未经检查的转换。在我们的例子中,如果使用GroupsCategory只有GroupObject,那么这是安全的,CategoryObject<GroupsCategory, E>没有不同的实现。

public interface Category<C extends Category<C>> 
{ 
    <E> CategoryObject<C, E> 
    castToConcreteObject(CategoryObject<C, E> abstractObject); 

    < DOM_E, COD_E 
    , DOM_CO extends CategoryObject<C, DOM_E> 
    , COD_CO extends CategoryObject<C, COD_E> 
    > 
    Binary<DOM_E, DOM_E, Boolean> 
    morphismTester (final Unary<DOM_E, COD_E> f 
        , DOM_CO domainObject 
        , COD_CO codomainObject 
        ); 
} 


public interface CategoryObject<C extends Category<C>, E> 
{ 
    Binary<E,E,Boolean> eq(); 
} 


public interface GroupObject<E> 
     extends CategoryObject<GroupsCategory, E> 
{ 
    E plus(E a, E b); 

    E invert(E a); 

    @Override 
    Binary<E,E,Boolean> eq(); 
} 

public class GroupsCategory 
    implements Category<GroupsCategory> 
{ 
    @Override 
    public <E> 
    GroupObject<E> 
    castToConcreteObject(CategoryObject<GroupsCategory, E> abstractObject) 
    { 
     return (GroupObject<E>) abstractObject; 
    } 

    @Override 
    public < DOM_E, COD_E 
      , DOM_CO extends CategoryObject<GroupsCategory, DOM_E> 
      , COD_CO extends CategoryObject<GroupsCategory, COD_E> 
      > 
    Binary<DOM_E, DOM_E, Boolean> 
    morphismTester (final Unary<DOM_E, COD_E> f 
        , final DOM_CO abstractDomainObject 
        , final COD_CO abstractCodomainObject 
        ) 
    { 
     final GroupObject<DOM_E> domainGroup 
      = castToConcreteObject(abstractDomainObject); 
     final GroupObject<COD_E> codomainGroup 
      = castToConcreteObject(abstractCodomainObject); 

     return new Binary<DOM_E, DOM_E, Boolean>() 
     { 
      @Override 
      public Boolean ap(DOM_E a, DOM_E b) 
      { 
       return codomainGroup.eq().ap 
        (
         codomainGroup.plus(f.ap(a), f.ap(b)), 
         f.ap(domainGroup.plus(a, b)) 
        ); 
      } 
     }; 
    } 
} 

可能要检查更多属性,您需要为每个属性定义一个类别。然后可能会有其他几个类别的扩展,这就是描述它们之间物体属性和态射之间的关系。

+0

这比我想要做的要少一些,它不会做我正在寻找的那种抽象。 Set态射的关键属性是他们通过equals。群体态度被设置为态度,也可以通过加。环态射体是群体态射也可以与时间交流。我想编写捕捉这个通用结构的“CommutesWith”函数。随着你的接近,即使是在铸造时,我也必须写出基本相同的功能来检查环状姆,组霍姆和设定霍姆斯。 – mdgeorge

1

作为第一近似,见代码在

https://github.com/rfqu/CodeSamples/blob/master/src/so/SoFun.java

至少它编译没有警告和错误:)

+0

这非常接近我的想法(另请参阅我发布的代码)。但施放者专门针对群组:我无法实现EqApplier(对于套件)和TimesApplier(对于戒指)。 – mdgeorge

+0

@mdgeorge查看其他变体:https://github.com/rfqu/CodeSamples/blob/master/src/so/SoFun2.java –

+0

这里使用访问者模式的问题是它将应用程序限制为整数和有理数。实际上有一类适用于所有类型的类。 – mdgeorge