2012-10-26 4 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)); 
} 

: "두 E 's의 소요와 R이 생산 진 기능 f 작동 예를 들어

, 여기 함수 교환 법칙이 성립되는지 확인하는 기능입니다 어떤 a 입력 Eb 대한 f(a,b)인가 가환 경우 (두 R 년대 비교 함수 eq 의해 정의와 같음), (b,a)인가 f 같다. "

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()); 

을 모두 잘하고 좋은 :

나는 다음 주어진 함수 C.plus(Integer,Integer)는 다음을 수행하여 교환 법칙이 성립하는지 테스트 할 수 있습니다.

이제 좀 더 복잡한 것을 구현하고 싶습니다. TheIntegersTheRationals : 나는 두 가지 구현이

interface Group<E> { 
    E plus(E,E); 
} 

하는의 말을하자의 내가 더하기 방법으로 일반적인 인터페이스 Group<E> 있다고 가정 해 봅시다 이제

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

을, 나는 아이디어를 캡처 할 수 있도록하려는 일반 함수 F은 정수에서 rationalals까지 과 같은 함수 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의 형태가 무엇을해야입니다 제 1 컷, 나는 이런 식으로 뭔가를 쓰고 싶어? 문제는 이 ER의 두 가지 유형에 적용된다는 것입니다. 구체적인 예에서 gGroup<Integer>.plus(Integer,Integer)Group<Fraction>.plus(Fraction,Fraction)을 모두 나타내야합니다.

이제 g.ap에 대한 두 호출 간의 유일한 구분이 지워지는 제네릭 형식이기 때문에 위의 checkCommutesWith 구현이 작동하지 않을 수 있습니다.

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 자바는 템플릿 템플릿 매개 변수에 해당이 없습니다. 그게 내가 붙어있는 곳이야.

다른 구조에서도이 코드를 사용할 수 있기를 원하기 때문에 그룹에 checkCommutesWith의 서명을 포함하고 싶지 않습니다. 일반 정의가 가능해야한다고 생각합니다 ("should"의 정의에 따라).)

업데이트/설명 여기서 중요한 점은 세트 간 맵의 정의 속성은 eq()로 통근한다는 것입니다. 집단 동형어 변성의 특징은 plus()로 통근한다는 것이다. 고리 동형 이형성의 정의 적 특성은 시간()으로 통근한다는 것이다. 이 아이디어를 캡처하는 일반적인 commutesWith 함수를 정의하려고합니다. eq, plus 및 times (및 다른 구조도 캡슐화하는 데 적합한 추상화를 찾고 있습니다.

+0

전략 패턴 – rees

+0

없이 컴파일

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

에서 코드를 볼 "문제는 g는 두 가지 유형에 적용된다 : E와 R ". 그렇다면 문제는 Java가 아닌 디자인에 있습니다. 자바는 그렇게 할 수 없을 때 옳다. 그러한 함수 g가 의미가있는 곳에서 더 구체적인 예를 들어 주시겠습니까? –

+0

@AlexeiKaigorodov : plus() 함수를 생각해보십시오. 그룹에 하나의 그룹과 두 그룹의 요소를 제공하면 해당 그룹의 요소를 제공해야합니다. TheRationals에 적용하여 한 쌍의 이성에서 합리적인 것으로 함수를 만들고 TheIntegers로 정수에서 정수로 함수를 가져와야합니다. 마찬가지로, times()는 반지와 함께 제공 될 때, 그리고 그 반지의 두 요소는 저에게 반지의 요소를 제공해야합니다. 따라서 캡슐화하려는 공통 구조는 임의의 T에 대해 > E ap (S, E, E) 형식의 함수입니다. – mdgeorge

답변

1

귀하의 목적에 맞지 않겠지 만 JScience 라이브러리에 정의 된 유형 구조를 검토 할 수 있습니다. 특히 org.jscience.mathematics.structure에 지정된 인터페이스는 유용한 시작점을 나타낼 수 있습니다.

+1

실제로 구현하려고하는 것과 매우 비슷하지만 여기서 요구하는 특정 기능을 제공하지는 않습니다. 이 패키지에서는 수학적 객체가 필요한 속성을 만족한다고 가정하는 반면, 단위 테스트를위한 프레임 워크를 작성하려고합니다. – mdgeorge

1

자바 타이핑 시스템이 체크되지 않은 캐스트없이이를 수행 할 수있을만큼 강하지 않을까봐 걱정됩니다. 그러나 그 영향을 최소화 할 수 있습니다.

이 내용을 Category-theoretical 용어로 정의하십시오. 이것은 모든 것에 대해 표현할만큼 일반적이며, 그룹 동질성은 범주 객체 사이의 변이의 구체적인 경우입니다.

아래 코드에 대한 참고 사항 : 1. checkCommutesWithmorphismTester 관계로 카레. 2. eq은 이제 매개 변수가 아닌 CategoryObject의 속성입니다. 3. castToConcreteObjectCategory 인 경우 검사되지 않은 캐스트를 만드는 데 사용됩니다. 이 예에서는 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 morphisms의 주요 속성은 equals로 통근하는 것입니다. 그룹 모피즘은 플러스로 통근하는 모피즘으로 설정됩니다. 고리 형태는 시간에 따라 통근하는 집단 형태이다. 이 일반적인 구조를 캡처하는 "CommutesWith"함수를 작성하고 싶습니다. 당신이 접근 할 때, 심지어 캐스팅을 할 때, 나는 링 homs, 그룹 homs 및 homs를 확인하기 위해 본질적으로 동일한 기능을 써야 할 것입니다. – mdgeorge

1

제 근사치로서 적어도 경고와 에러 :)

+0

그건 내가 마음에 두었던 것에 매우 가깝다. 그러나 applier는 Group에게 전문화되어 있습니다. EqApplier (집합의 경우)와 TimesApplier (링의 경우)를 구현할 수 없습니다. – mdgeorge

+0

@morgeorge 다른 변형을 살펴보십시오. https://github.com/rfqu/CodeSamples/blob/master/src/so/SoFun2.java –

+0

visitor 패턴을 사용할 때의 문제는 applier를 정수와 합계로 제한한다는 것입니다 . 실제로 플러스가 적용되는 유형의 전체 클래스가 있습니다. – mdgeorge