haskell - salsa - un amor como el nuestro
¿Qué hay de malo en OverlappingInstances? (1)
Un principio que el lenguaje haskell intenta acatar es agregar métodos / clases o instancias adicionales en un módulo dado que no debe hacer que otros módulos que dependen del módulo dado no compilen o tengan un comportamiento diferente (siempre que los módulos dependientes utilizar listas de importación explícitas).
Desafortunadamente, esto se rompe con OverlappingInstances. Por ejemplo:
Módulo A:
{-# LANGUAGE FlexibleInstances, OverlappingInstances, MultiParamTypeClasses, FunctionalDependencies #-}
module A (Test(..)) where
class Test a b c | a b -> c where
test :: a -> b -> c
instance Test String a String where
test str _ = str
Módulo B:
module B where
import A (Test(test))
someFunc :: String -> Int -> String
someFunc = test
shouldEqualHello = someFunc "hello" 4
shouldEqualHello
es igual a "hola" en el módulo B.
Ahora agregue la siguiente declaración de instancia en A:
instance Test String Int String where
test s i = concat $ replicate i s
Sería preferible que esto no afectara al módulo B. Funcionó antes de esta adición y debería funcionar después. Desafortunadamente, este no es el caso.
El módulo B aún se compila, pero ahora shouldEqualHello
ahora es igual a "hellohellohellohello"
. El comportamiento ha cambiado a pesar de que ningún método que estaba utilizando originalmente había cambiado.
Lo que es peor es que no hay manera de volver al comportamiento anterior, ya que no puede elegir no importar una instancia desde un módulo. Como puede imaginar, esto es muy malo para la compatibilidad con versiones anteriores, ya que no puede agregar de manera segura nuevas instancias a una clase que usa instancias superpuestas, ya que podría cambiar el comportamiento del código que usa el módulo (especialmente si está escribiendo un código de biblioteca). Esto es peor que un error de compilación, ya que podría ser muy difícil rastrear el cambio.
En mi opinión, el único momento seguro para usar instancias superpuestas es cuando escribe una clase que sabe que nunca necesitará instancias adicionales. Esto puede ocurrir si está haciendo algún tipo de código basado en la dificultad.
Apartando algunas de las preguntas recientes, me di cuenta de que iba a centrar la atención en el viejo cochero, OverlappingInstances
.
Hace unos años podría haber estado haciendo esta pregunta en serio: después de todo, puede proporcionar instancias predeterminadas útiles y otros pueden anularlas con otras más específicas cuando lo necesitan, ¿qué puede ser tan malo?
En el camino he absorbido cierta apreciación por el punto de vista de que OverlappingInstances
realmente no es tan limpio, y es mejor evitarlo; principalmente debido al hecho de que no está muy bien fundamentado teóricamente, a diferencia de otras grandes extensiones.
Pero pensando en ello, no estoy seguro de poder explicar lo que realmente es tan malo a otra persona, si me lo pidieran.
Lo que estoy buscando son ejemplos específicos de las formas en que el uso de OverlappingInstances
puede llevar a que sucedan cosas malas, ya sea mediante la subversión del sistema de tipos u otros invariantes, o simplemente por una inesperada o desorden general.
Un problema particular que conozco es que rompe la propiedad de que simplemente agregar o eliminar una importación de un solo módulo no puede cambiar el significado de su programa, ya que con la extensión activada, se podría agregar o eliminar de manera silenciosa una nueva superposición de instancia. Si bien puedo ver por qué es desagradable, no veo por qué es terriblemente terrible.
Pregunta extra: Mientras estemos en el tema de extensiones útiles, pero no teóricamente bien fundamentadas, que puedan conducir a malos acontecimientos, ¿cómo es posible que GeneralizedNewtypeDeriving
no tenga la misma mala reputación? Es porque las posibilidades negativas son más fáciles de localizar; que es más fácil ver qué causaría problemas y decir "no hagas eso"?
(Nota: preferiría que la peor parte de la respuesta se centre en las OverlappingInstances
, no en las IncoherentInstances
que necesitan menos explicación).
EDITAR: También hay buenas respuestas a una pregunta similar here .