2009-05-18 2 views
28

나는 다음과 같은 클래스가 있다고 가정높은-kinded 제네릭

public class FixExpr { 
    Expr<FixExpr> in; 
} 

가 지금은 EXPR의 사용에 추상화, 일반적인 인수를 소개합니다 :

public class Fix<F> { 
    F<Fix<F>> in; 
} 

을하지만 이클립스 '아무튼를 이런 식으로 :

유형 F는 일반적인 것이 아닙니다. <F> >

수정 < 인수와 함께이 전혀 가능 매개 변수화 할 수 없거나 나는이 특정 인스턴스가 중단됩니다 뭔가를 간과?

일부 배경 정보 : 하스켈에서는 일반적인 함수를 작성하는 일반적인 방법입니다. 나는 이것을 자바로 포팅하려고 노력하고있다. 위의 예제에서 type 인수 F는 일반적인 종류 * 대신 * -> *를 사용합니다. 하스켈 그것은 다음과 같다 : 타입 파라미터를 전달하기 위해

newtype Fix f = In { out :: f (Fix f) } 
+1

이 함께 해결하려고하는 실제 문제가 무엇입니까? 템플릿을 사용하여 더 쉽게 해결할 수 없습니까? – KitsuneYMG

답변

23

나는 무엇을 당신이하려는 것은 단순히 아니라고 생각 Java generics가 지원합니다.

public class Foo<T> { 
    public T<String> bar() { return null; } 
} 

의 간단한 경우도 javac를 사용하여 컴파일하지 않습니다.

Java는 컴파일시에 T이 무엇인지 알지 못하기 때문에 T<String>이 모두 의미 있음을 보장 할 수 없습니다.당신이 Foo<BufferedImage>을 만든 경우 예를 들어, bar은 무의미 서명

public BufferedImage<String> bar() 

있을 것입니다. T을 사용하여 Foo을 인스턴스화하도록 강제하는 메커니즘이 없으므로 컴파일을 거부합니다.

5

는 타입 정의 (이것은일반이어야한다)가 하나를 수락 함을 선언한다. 분명히 F은 제네릭 유형이 아닙니다.

UPDATE : 라인

F<Fix<F>> in; 

자체 타입 파라미터를 수용 Fix되는 값하는 유형 파라미터를 수락 형 F의 변수를 선언하고,이 값은 어느 F이다. 귀하의 예에서는 F도 정의되어 있지 않습니다. 난 당신이 당신에게 유형 Fix (당신이 한 유형이 예에서 정의)이 값 F와 유형 매개 변수를 전달하는 수의 변수를 줄 것이다

Fix<F> in; 

을 할 수 있습니다 생각합니다. Fix이 유형 매개 변수를 허용하도록 정의되었으므로이 방법이 유용합니다.

업데이트 2 : 제목을 다시 읽으십시오. 이제 "Towards Equal Rights for Higher-Kinded Types" (PDF 알림)과 비슷한 방식으로 작업하려고 할 것입니다. 그렇다면 Java는이를 지원하지 않지만 Scala를 사용해보십시오.

+0

조금 더 자세히 설명해 주시겠습니까? 형식 매개 변수를 받아들이도록 형식을 선언했습니다. - Fix . 아니면이게 무슨 뜻이 아니야? – Martijn

+0

그러나 선택한 유형 (>)은 일반적이지 않습니다. 수정 에 대해서만 작동합니다 - 반드시 유형으로 선언해야합니다. – sanbikinoraion

+0

그 종이 흥미 롭습니다 - 고마워요! – Martijn

0

그것은 당신이 같은 것을 할 수있는 것처럼 보인다 : (.의 제네릭에 대한 참조 열거 클래스 및 질문)

public class Fix<F extends Fix<F>> { 
    private F in; 
} 

+0

안녕하세요 톰, 그 솔루션은 정말 재미있어 보이지만 난 아직도 그것이 무엇을 얻을지 않습니다. F에 어떤 계층 구조를 부과하지 않습니까? 나는 그것을하고 싶지 않습니다. F에 대해 묻는 것은 그것이 완성 될 수있는 형식의 인수를 여전히 받는다는 것입니다. – Martijn

+0

그렇다면 java에서 원하는 것을 수행 할 수 없습니다. 언어가 충분히 표현할 수 없습니다. – Chii

+0

그것은 F가 수정 유형이라고 말합니다. Fix는 generic이기 때문에 올바른 generic 인수가 주어져야합니다. 귀하의 질문은 매우 추상적입니다. 하스켈은 Java와는 다른 복잡한 유형의 시스템을 가지고 있음을 이해합니다. 모든 기능에 대해 1 : 1지도가 없다는 것은 놀라운 일이 아닙니다. –

24

아마도 JVM에서 실행되는 기능적 언어 인 스칼라 (Scala)를 사용해보십시오. 스칼라는 더 높은 종류의 제네릭을 지원합니다.


[Rahul G에 의해 편집]

여기에 특정 예를 대략 스칼라로 변환하는 방법은 다음과 같습니다

trait Expr[+A] 

trait FixExpr { 
    val in: Expr[FixExpr] 
} 

trait Fix[F[_]] { 
    val in: F[Fix[F]] 
} 
1

아직도, 자바 higer-kinded 제네릭을 인코딩하는 방법이 있습니다. 제발, higher-kinded-java project 좀 봐. 라이브러리로이 사용

,이 같은 코드를 수정할 수 있습니다

public class Fix<F extends Type.Constructor> { 
    Type.App<F, Fix<F>> in; 
} 

당신은 아마 당신의 Expr 클래스

@GenerateTypeConstructor 
public class Expr<S> { 
    // ... 
} 

이 주석이 ExprTypeConstructor 클래스를 생성에 @GenerateTypeConstructor 주석을 추가해야합니다. 지금 당신은 다음과 같이 EXPR의 당신의 수정을 처리 할 수 ​​있습니다 :

class Main { 
    void run() { 
     runWithTyConstr(ExprTypeConstructor.get); 
    } 

    <E extends Type.Constructor> void runWithTyConstr(ExprTypeConstructor.Is<E> tyConstrKnowledge) { 
     Expr<Fix<E>> one = Expr.lit(1); 
     Expr<Fix<E>> two = Expr.lit(2); 

     // convertToTypeApp method is generated by annotation processor 
     Type.App<E, Fix<E>> oneAsTyApp = tyConstrKnowledge.convertToTypeApp(one); 
     Type.App<E, Fix<E>> twoAsTyApp = tyConstrKnowledge.convertToTypeApp(two); 

     Fix<E> oneFix = new Fix<>(oneAsTyApp); 
     Fix<E> twoFix = new Fix<>(twoAsTyApp); 

     Expr<Fix<E>> addition = Expr.add(oneFix, twoFix); 
     process(addition, tyConstrKnowledge); 
    } 

    <E extends Type.Constructor> void process(
      Fix<E> fixedPoint, 
      ExprTypeConstructor.Is<E> tyConstrKnowledge) { 

     Type.App<E, Fix<E>> inTyApp = fixedPoint.getIn(); 

     // convertToExpr method is generated by annotation processor 
     Expr<Fix<E>> in = tyConstrKnowledge.convertToExpr(inTyApp); 

     for (Fix<E> subExpr: in.getSubExpressions()) { 
      process(subExpr, tyConstrKnowledge); 
     } 
    } 

} 
관련 문제