¿Cuáles son algunas técnicas que podría utilizar para refactorizar constantemente el código eliminando la dependencia de los tipos existenciales? Por lo general, estos se usan para descalificar construcciones no deseadas de su tipo, así como para permitir el consumo con un mínimo conocimiento sobre el tipo dado (o eso es lo que entiendo).
¿Alguien ha encontrado una manera simple y consistente de eliminar la dependencia de estos en el código que aún mantiene algunos de los beneficios? ¿O al menos alguna forma de deslizarse en una abstracción que permita su eliminación sin requerir un cambio significativo de código para hacer frente a la alteración?
Puedes leer más sobre los tipos existenciales aquí ("si te atreves ...").
functional-programming
haskell
type-systems
Petr Pudlák
fuente
fuente
Respuestas:
Los tipos existenciales no se consideran realmente una mala práctica en la programación funcional. Creo que lo que te está tropezando es que uno de los usos más comúnmente citados para los existenciales es el antipatrón de clase de tipo existencial , que mucha gente cree que es una mala práctica.
Este patrón a menudo se presenta como una respuesta a la pregunta de cómo tener una lista de elementos de tipo heterogéneo que implementen la misma clase de tipos. Por ejemplo, es posible que desee tener una lista de valores que tengan
Show
instancias:El problema con un código como este es este:
AnyShape
es obtener su área.AnyShape
constructor para incorporar uno de los tipos de formas alAnyShape
tipo.Resulta que ese código realmente no te da nada que este más corto no:
En el caso de las clases de métodos múltiples, el mismo efecto generalmente se puede lograr de manera más simple mediante el uso de una codificación de "registro de métodos"; en lugar de usar una clase de tipo como
Shape
, usted define un tipo de registro cuyos campos son los "métodos" delShape
tipo , y escribes funciones para convertir tus círculos y cuadrados enShape
s.¡Pero eso no significa que los tipos existenciales sean un problema! Por ejemplo, en Rust tienen una característica llamada objetos de rasgos que las personas a menudo describen como un tipo existencial sobre un rasgo (las versiones de Rust de las clases de tipos). Si las clases de tipos existenciales son un antipatrón en Haskell, ¿eso significa que Rust eligió una mala solución? ¡No! La motivación en el mundo de Haskell es sobre la sintaxis y la conveniencia, no sobre el principio.
Una forma más matemática de decir esto es señalar que el
AnyShape
tipo de arriba yDouble
son isomórficos : hay una "conversión sin pérdidas" entre ellos (bueno, salvo la precisión de coma flotante):Hablando estrictamente, no estás ganando o perdiendo ningún poder eligiendo uno contra el otro. Lo que significa que la elección debe basarse en otros factores como la facilidad de uso o el rendimiento.
Y tenga en cuenta que los tipos existenciales tienen otros usos fuera de este ejemplo de listas heterogéneas, por lo que es bueno tenerlos. Por ejemplo, el
ST
tipo de Haskell , que nos permite escribir funciones que son externamente puras pero utilizan internamente operaciones de mutación de memoria, utiliza una técnica basada en tipos existenciales para garantizar la seguridad en el momento de la compilación.Entonces, la respuesta general es que no hay una respuesta general. Los usos de los tipos existenciales solo pueden juzgarse en contexto, y las respuestas pueden ser diferentes dependiendo de las características y la sintaxis proporcionadas por los diferentes idiomas.
fuente
No estoy demasiado familiarizado con Haskell, por lo que intentaré responder la parte general de la pregunta como desarrollador funcional no académico de C #.
Después de leer un poco, resulta que:
Los comodines de Java son similares a los tipos existenciales:
Diferencia entre los tipos existenciales de Scala y el comodín de Java por ejemplo
Los comodines no se implementan en C # completamente: se admite la variación genérica, pero la variación del sitio de llamada no:
Genéricos C #: comodines
Es posible que no necesite esta característica todos los días, pero cuando lo haga, la sentirá (por ejemplo, tener que introducir un tipo adicional para que las cosas funcionen):
Comodines en restricciones genéricas de C #
Sobre la base de esta información, los tipos / comodines existenciales son útiles cuando se implementan correctamente y no hay nada de malo en ellos per se, pero probablemente se puedan usar de forma incorrecta al igual que otras características del lenguaje.
fuente