Ya no tienes que investigar más por todo internet ya que estás al lugar exacto, tenemos la respuesta que deseas pero sin complicaciones.
Solución:
Yo diría que una interfaz es como una clase de tipo. SomeInterface t
donde todos los valores tienen el tipo t -> whatever
(donde whatever
no contiene t
). Esto se debe a que con el tipo de relación de herencia en Java y lenguajes similares, el método llamado depende del tipo de objeto al que se llama, y nada más.
Eso significa que es muy difícil hacer cosas como add :: t -> t -> t
con una interfaz, donde es polimórfico en más de un parámetro, porque no hay forma de que la interfaz especifique que el tipo de argumento y el tipo de retorno del método es del mismo tipo que el tipo de objeto en el que se llama (es decir, el tipo “yo”). Con Generics, hay formas de falsificar esto creando una interfaz con un parámetro genérico que se espera que sea del mismo tipo que el objeto en sí, como cómo Comparable
lo hace, donde se espera que use Foo implements Comparable
de manera que la compareTo(T otherobject)
tipo de tiene tipo t -> t -> Ordering
. Pero eso aún requiere que el programador siga esta regla, y también causa dolores de cabeza cuando la gente quiere hacer una función que use esta interfaz, tienen que tener parámetros recursivos de tipo genérico.
Además, no tendrás cosas como empty :: t
porque no está llamando a una función aquí, por lo que no es un método.
Lo que es similar entre interfaces y clases de tipos es que nombran y describen un conjunto de operaciones relacionadas. Las operaciones en sí se describen mediante sus nombres, entradas y salidas. Asimismo, puede haber muchas implementaciones de estas operaciones que probablemente diferirán en su implementación.
Con eso fuera del camino, aquí hay algunas diferencias notables:
- Los métodos de interfaz siempre están asociados con una instancia de objeto. En otras palabras, siempre hay un parámetro ‘this’ implícito que es el objeto en el que se llama al método. Todas las entradas a una función de clase de tipo son explícitas.
- Una implementación de interfaz debe definirse como parte de la clase que implementa la interfaz. A la inversa, una clase de tipo ‘instancia’ se puede definir completamente separada de su tipo asociado … incluso en otro módulo.
En general, creo que es justo decir que las clases de tipos son más potentes y flexibles que las interfaces. ¿Cómo definiría una interfaz para convertir un string a algún valor o instancia del tipo de implementación? Ciertamente no es imposible, pero el resultado no sería intuitivo ni elegante. ¿Alguna vez ha deseado que fuera posible implementar una interfaz para un tipo en alguna biblioteca compilada? Ambos son fáciles de lograr con clases de tipos.
Las clases de tipos se crearon como una forma estructurada de expresar “polimorfismo ad-hoc”, que es básicamente el término técnico para funciones sobrecargadas. Una definición de clase de tipo se parece a esto:
class Foobar a where
foo :: a -> a -> Bool
bar :: String -> a
Lo que esto significa es que, cuando usa aplicar la función foo
a algunos argumentos de un tipo que pertenecen a la clase Foobar
, busca una implementación de foo
específico para ese tipo, y lo usa. Esto es muy similar a la situación con la sobrecarga de operadores en lenguajes como C ++ / C #, excepto que es más flexible y generalizado.
Las interfaces tienen un propósito similar en los lenguajes OO, pero el concepto subyacente es algo diferente; Los lenguajes OO vienen con una noción incorporada de jerarquías de tipos que Haskell simplemente no tiene, lo que complica las cosas de alguna manera porque las interfaces pueden involucrar tanto la sobrecarga por subtipos (es decir, llamar a métodos en instancias apropiadas, subtipos que implementan interfaces que hacen sus supertipos) y por despacho basado en tipo plano (ya que dos clases que implementan una interfaz pueden no tener una superclase común que también la implemente). Dada la enorme complejidad adicional introducida por el subtipo, sugiero que es más útil pensar en las clases de tipos como una versión mejorada de funciones sobrecargadas en un lenguaje que no sea OO.
También vale la pena señalar que las clases de tipos tienen medios de distribución mucho más flexibles: las interfaces generalmente se aplican solo a la clase única que la implementa, mientras que las clases de tipos se definen para un escribe, que puede aparecer en cualquier parte de la firma de las funciones de la clase. El equivalente de esto en las interfaces OO sería permitir que la interfaz defina formas de pasar un objeto de esa clase a otras clases, definir static métodos y constructores que seleccionarían una implementación en función de lo que tipo de retorno es necesario para llamar al contexto, definir métodos que tomen argumentos del mismo tipo que la clase que implementa la interfaz y varias otras cosas que realmente no se traducen en absoluto.
En resumen: sirven para propósitos similares, pero la forma en que funcionan es algo diferente, y las clases de tipos son significativamente más expresivas y, en algunos casos, más simples de usar debido a que trabajan con tipos fijos en lugar de partes de una jerarquía de herencia.
Recuerda que puedes optar por la opción de interpretar si te fue de ayuda.