En muchos años de programación OO, he entendido lo que son los sindicatos discriminados, pero nunca los extrañé realmente. Recientemente he estado haciendo una programación funcional en C # y ahora encuentro que sigo deseando tenerlos. Esto me desconcierta porque, a primera vista, el concepto de uniones discriminadas parece bastante independiente de la dicotomía funcional / OO.
¿Hay algo inherente en la programación funcional que hace que las uniones discriminadas sean más útiles de lo que serían en OO, o es que al obligarme a analizar el problema de una manera "mejor", simplemente he mejorado mis estándares y ahora exijo una mejor ¿modelo?
Respuestas:
Las uniones discriminadas realmente brillan junto con la coincidencia de patrones, donde se selecciona un comportamiento diferente según los casos. Pero este patrón es fundamentalmente antitético a los principios de OO puro.
En OO puro, las diferencias de comportamiento deben definirse por los tipos (objetos) en sí mismos y encapsularse. Por lo tanto, la equivalencia con la coincidencia de patrones sería llamar a un método único en el objeto mismo, que luego se sobrecarga por los subtipos en cuestión para definir un comportamiento diferente. Inspeccionar el tipo de un objeto desde el exterior (que es lo que hace la coincidencia de patrones) se considera un antipatrón.
La diferencia fundamental es que los datos y el comportamiento están separados en la programación funcional, mientras que los datos y el comportamiento están encapsulados en OO.
Esta es la razón histórica. Un lenguaje como C # se está desarrollando desde un lenguaje OO clásico hasta un lenguaje de paradigmas múltiples al incorporar más y más funciones.
fuente
List<A>
el métodoB Match<B>(B nil, Func<A,List<A>,B> cons)
. Por ejemplo, este es exactamente el patrón que Smalltalk usa para los booleanos. Esto también es básicamente cómo lo maneja Scala. Que se usen varias clases es un detalle de implementación que no necesita ser expuesto.isEmpty
método que verifica si la referencia al siguiente nodo es nula.Habiendo programado en Pascal y Ada antes de aprender programación funcional, no asocio uniones discriminadas con programación funcional.
Las uniones discriminadas son de alguna manera el doble de la herencia. El primero permite agregar fácilmente operaciones en un conjunto fijo de tipos (aquellos en la unión), y la herencia permite agregar fácilmente tipos con un conjunto fijo de operaciones. (Cómo agregar fácilmente ambos se llama problema de expresión ; ese es un problema especialmente difícil para los idiomas con un sistema de tipo estático).
Debido al énfasis de OO en los tipos y al doble énfasis de la programación funcional en las funciones, los lenguajes de programación funcional tienen una afinidad natural por los tipos de unión y ofrecen estructuras sintácticas para facilitar su uso.
fuente
Las técnicas de programación imperativa, como se usan a menudo en OO, se basan a menudo en dos patrones:
null
a indicar "sin valor" o error.El paradigma funcional generalmente evita ambos, prefiriendo devolver un tipo compuesto que indique la razón de éxito / fracaso o valor / no valor.
Los sindicatos discriminados se ajustan al proyecto de ley para estos tipos compuestos. Por ejemplo, en primera instancia, puede regresar
true
, o alguna estructura de datos que describa la falla. En el segundo caso, una unión que contiene un valor, onone
,nil
etc. El segundo caso es tan común que muchos lenguajes funcionales tienen un tipo "quizás" u "opción" incorporado para representar ese valor / ninguna unión.Al cambiar a un estilo funcional con, por ejemplo, C #, encontrará rápidamente la necesidad de estos tipos compuestos.
void/throw
ynull
simplemente no me siento bien con ese código. Y los sindicatos discriminados (DU) se ajustan bien a la ley. Por lo tanto, te encontraste deseándolos, al igual que muchos de nosotros.La buena noticia es que hay muchas bibliotecas por ahí que modelan DUs en, por ejemplo, C # (eche un vistazo a mi propia biblioteca Succinc <T> , por ejemplo).
fuente
Los tipos de suma serían generalmente menos útiles en los lenguajes OO convencionales, ya que están resolviendo un tipo de problema similar al subtipo OO. Una forma de verlos es que ambos manejan
open
subtipos, pero OO es, es decir, uno puede agregar subtipos arbitrarios a un tipo primario y los tipos de suma son,closed
es decir, uno determina por adelantado qué subtipos son válidos.Ahora, muchos lenguajes OO combinan el subtipo con otros conceptos, como estructuras heredadas, polimorfismo, mecanografía de referencia, etc. para que sean generalmente más útiles. Una consecuencia es que tienden a ser más trabajos de configuración (con clases y constructores y demás), por lo que tienden a no usarse para cosas como
Result
syOption
s y así sucesivamente hasta que la tipificación genérica se hizo común.También diría que el enfoque en las relaciones del mundo real que la mayoría de la gente aprendió cuando comenzaron la programación OO, por ejemplo, Dog isa Animal, significaba que Integer is a Result o Error isa Result parece un poco extraño. Aunque las ideas son bastante similares.
En cuanto a por qué los lenguajes funcionales podrían preferir la escritura cerrada a la abierta, una posible razón es que tienden a preferir la coincidencia de patrones. Esto es útil para el polimorfismo de la función, pero también funciona muy bien con tipos cerrados ya que el compilador puede verificar estáticamente que la coincidencia cubre todos los subtipos. Esto puede hacer que el lenguaje se sienta más consistente, aunque no creo que haya ningún beneficio inherente (podría estar equivocado).
fuente
sealed
significa "solo se puede extender en la misma unidad de compilación", lo que le permite cerrar el conjunto de subclases en tiempo de diseño.Swift felizmente usa sindicatos discriminatorios, excepto que los llama "enumeraciones". Las enumeraciones son una de las cinco categorías fundamentales de objetos en Swift, que son clase, estructura, enumeración, tupla y cierre. Los opcionales Swift son enumeraciones que son uniones discriminatorias, y son absolutamente esenciales para cualquier código Swift.
Por lo tanto, la premisa de que "los sindicatos discriminatorios están asociados con la programación funcional" es errónea.
fuente