studio programacion para móviles libro edición desarrollo curso aplicaciones java generics haskell polymorphism higher-kinded-types

java - para - manual de programacion android pdf



Genéricos de clase superior en Java (5)

Supongamos que tengo la siguiente clase:

public class FixExpr { Expr<FixExpr> in; }

Ahora quiero presentar un argumento genérico, resumiendo sobre el uso de Expr:

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

Pero a Eclipse no le gusta esto:

El tipo F no es genérico; no se puede parametrizar con argumentos <Fix <F>>

¿Es esto posible o he pasado por alto algo que hace que esta instancia específica se rompa?

Alguna información de fondo: en Haskell esta es una forma común de escribir funciones genéricas; Estoy tratando de portar esto a Java. El argumento de tipo F en el ejemplo anterior tiene el tipo * -> * en lugar del tipo usual *. En Haskell se ve así:

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


Creo que lo que estás tratando de hacer simplemente no es compatible con los genéricos de Java. El caso más sencillo de

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

Tampoco compila utilizando javac.

Ya que Java no sabe en tiempo de compilación qué es T , no puede garantizar que T<String> sea ​​en absoluto significativo. Por ejemplo, si creaste una Foo<BufferedImage> , la bar tendría la firma

public BufferedImage<String> bar()

lo cual es absurdo. Dado que no existe un mecanismo para forzarlo a crear solo instancias de Foo con T genéricas, se niega a compilar.


Para pasar un parámetro de tipo, la definición de tipo tiene que declarar que acepta uno (tiene que ser genérico ). Aparentemente, tu F no es un tipo genérico.

ACTUALIZACIÓN: La línea.

F<Fix<F>> in;

declara una variable de tipo F que acepta un parámetro de tipo, cuyo valor es Fix , que a su vez acepta un parámetro de tipo, cuyo valor es F F ni siquiera está definido en tu ejemplo. Creo que puedes querer

Fix<F> in;

Eso le dará una variable de tipo Fix (el tipo que definió en su ejemplo) a la que está pasando un parámetro de tipo con el valor F Como Fix está definido para aceptar un parámetro de tipo, esto funciona.

ACTUALIZACIÓN 2: Vuelva a leer su título, y ahora creo que podría estar tratando de hacer algo similar al enfoque presentado en "Hacia la igualdad de derechos para los tipos de mayor vínculo" (alerta de PDF). Si es así, Java no lo admite, pero puedes probar con Scala.


Parece como si quisieras algo como:

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

(Consulte la clase Enum y las preguntas sobre sus genéricos).


Sin embargo, hay formas de codificar genéricos de clase alta en Java. Por favor, eche un vistazo al proyecto java de más alto nivel .

Usando esto como una biblioteca, puedes modificar tu código así:

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

Probablemente debería agregar una anotación @GenerateTypeConstructor a su clase Expr

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

Esta anotación genera la clase ExprTypeConstructor. Ahora puedes procesar tu Corrección de Expr así:

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


Tal vez puedas probar Scala, que es un lenguaje funcional que se ejecuta en JVM, que admite genéricos de alto nivel.

[EDIT por Rahul G ]

Aquí es cómo su ejemplo particular se traduce aproximadamente a Scala:

trait Expr[+A] trait FixExpr { val in: Expr[FixExpr] } trait Fix[F[_]] { val in: F[Fix[F]] }