¿Podría la inferencia Hindley-Milner funcionar para el idioma Go?

22

He leído que Hindley-Milner no funciona con sistemas de tipos que tienen subclases, y hay otras características del sistema de tipos que tampoco funcionan bien con él. Go actualmente solo tiene una inferencia de tipos muy limitada en el :=operador. Pero Go no tiene subclases en el sentido tradicional, solo interfaces que se parecen mucho a las clases de tipos de Haskell que funcionan bien con la inferencia Hindley-Milner.

Entonces, ¿podría la inferencia Hindley-Milner funcionar en principio para Go de la misma manera que para Haskell? ¿O Go tiene otras características que lo rompen? (Por otro lado, Haskell también tiene algunas características que no funcionan con Hindly-Milner, si usa las que tiene que escribir manualmente esas partes de su programa).

JanKanis
fuente

Respuestas:

35

La inferencia de tipo Hindley-Milner se usa para sistemas de tipo Hindley-Milner, una restricción de los sistemas de tipo System-F. La característica interesante de los sistemas de tipo HM es que tienen polimorfismo paramétrico (también conocido como genéricos). Esa es la característica de sistema de tipo más grande que Golang se niega a tener.

Con esa restricción frustrante, la inferencia tipo HM es imposible. Veamos el código sin tipo:

func f(a) {
  return a.method()
}

¿De qué tipo es f? Podríamos notar que adebe tener un método, por lo que podríamos usar una interfaz anónimo: func f(a interface { method() ??? }) ???. Sin embargo, no tenemos idea de cuál es el tipo de retorno. Con las variables de tipo, podríamos declarar el tipo como

func f[T](a interface{ method() T }) T

Sin embargo, Go no tiene variables de tipo, por lo que esto no funcionará. Si bien las interfaces implícitas facilitan algunos aspectos de la inferencia de tipos, ahora no tenemos forma de averiguar el tipo de retorno de una llamada de función. El sistema HM requiere que todas las funciones se declaren en lugar de estar implícitas, y cada nombre solo puede tener un solo tipo (mientras que los métodos de Go pueden tener diferentes tipos en diferentes interfaces).

En cambio, Go requiere que las funciones siempre estén completamente declaradas, pero permite que las variables usen inferencia de tipos. Esto es posible porque el lado derecho de una tarea variable := expressionya tiene un tipo conocido en ese punto del programa. Este tipo de inferencia de tipos es simple, correcta y lineal.

  • El tipo de una variable se conoce inmediatamente en el punto de la declaración, mientras que la inferencia HM tiene que verificar primero todo el programa. Esto también tiene un impacto notable en la calidad de los mensajes de error.
  • El enfoque de inferencia de tipos de Go siempre seleccionará el tipo más específico para una variable, en contraste con HM, que elige el tipo más general. Esto funciona limpiamente con subtipificación, incluso con las interfaces implícitas de Go.
amon
fuente
24
@bishop Está "razonado" para valores infinitesimalmente pequeños de "razón".
hobbs
18
@bishop Habiendo hecho el trabajo de compilación en idiomas con genéricos, ciertamente puedo estar de acuerdo: es difícil de implementar sin complicar significativamente la implementación. Llegaría incluso a reemplazar "difícil" por "imposible". Sin embargo, ese no es el punto; El punto es, ¿vale la pena la complicación adicional? Y la respuesta, para cualquiera que haya trabajado con y sin genéricos, es obviamente "¡sí, definitivamente!" Tendría que estar totalmente de acuerdo con la afirmación de que negarse a implementar genéricos porque "oh no, la complejidad" es idiota.
Mason Wheeler
18
Esta es también la razón por la cual los desarrolladores de Go fingen que FP de todo tipo es malo; Go tiene funciones de primera clase con cierre de léxico, y con ello la capacidad de crear funciones de orden superior, pero es imposible poner a cualquier uso bueno porque los tipos de tales funciones básicas como map, filtery reduceson todos inexplicable dentro de GO es muy limitado sistema de tipos
hobbs
99
@hobbs And Go podría ser un lenguaje realmente agradable si se solucionara, pero en su lugar la gente tiene que escribir bibliotecas de generación genérica como gengenygonerics
cat
14
@cat Es una pena. Al principio, Go parece un gran lenguaje lleno de grandes ideas, pero luego te das cuenta de que no tiene herencia y polimorfismo, por lo que no puedes hacer OOP bien, y no tiene genéricos, por lo que no puedes hacer FP bien, y Te quedas mirando fijamente la pantalla preguntando "¿cómo se supone que debes usar este idioma?"
Mason Wheeler