paradigmas - ¿Haskell soporta programación orientada a objetos?
programacion funcional (4)
Las clases de tipo son de hecho las únicas construcciones que recuerdan de forma remota los conceptos OO, en este caso, en las interfaces. Aunque, a diferencia de Java, las clases de tipos no son tipos.
Una cosa buena acerca de las clases de tipo es que puedo hacer tipos totalmente independientes y no relacionados de una clase de tipo. Mientras que en java, a veces uno piensa: estas clases A del paquete org.a y B del com.b que estoy usando deberían realmente implementar la interfaz Y de un tercer paquete, pero no hay manera de hacerlo que no requiera una gran cantidad de código repetitivo, indirecciones adicionales, clasificación, etc.
Por cierto, como programador anciano, me gustaría señalar que "la separación de la declaración y la implementación" no tiene nada que ver con OOP. El hecho de que la mayoría de los OO-langugeas lo admitan no significa que el concepto no fuera bien conocido durante mucho tiempo antes de que se inventara OO. Los jóvenes interesados que piensan que la programación antes de la integración de OO debe haber estado en un nivel de "edad de piedra", pueden buscar MODULA, por ejemplo, donde la separación de la declaración y la implementación no solo es posible, sino que el lenguaje lo impone.
¿Admite conceptos como separación de declaración e implementación (interfaces y clases en Java)? ¿Qué hay de restringir el acceso (como los modificadores de acceso en Java)?
Gracias
Una cosa podría ser bueno mencionar es lenses . Le permiten escribir el tipo de "expresión" abcde
de una manera abcde
.
El .
se puede definir para cada estructura de datos. Entonces, en cierto sentido, el .
es un ciudadano de primera clase en Haskell. Se puede nombrar, almacenar, dos .
-s pueden ser compuestos, etc.
Vea el Sistema de objetos pasados por alto de Haskell por Oleg Kiselyov y Ralf Laemmel para una explicación detallada de cómo los conceptos OO se pueden implementar en Haskell. Pero como dijo Antal en los comentarios, no trates de escribir un programa Java en Haskell.
Recuerde que los objetos son el cierre de un hombre pobre, y los cierres son un objeto de los pobres.
¿Cómo separe la declaración y la implementación en Haskell?
En Haskell puedes definir una typeclass , que es bastante diferente de una clase orientada a objetos, así que no dejes que el nombre te engañe. Al usar la class
palabra clave, puede declarar nombres de funciones y firmas de tipos que se pueden instanciar (implementar) en otro lugar para un tipo de datos en particular.
Por ejemplo, la Hashable Hashable define la función hash
, que puede convertir cualquier tipo de datos instanciado en un Int
. ¿Tiene un tipo de datos nuevo y original que quiera hash? Bien, crea una instancia de Hashable. Los tipos de datos más comunes son instanciados por el módulo que define Hashable
(consulte la documentación vinculada para ''Instancias'').
Las clases de tipos no son la única forma de definir una interfaz. Un método que a menudo está infravalorado es una vieja estructura de datos simple. Como Haskell tiene funciones de primera clase, puede definir una estructura de datos que tenga funciones como campos:
data ShuttleInterface =
SI { launch :: Delay -> IO Handle
, deploy :: Payload -> IO ()
, getStatus :: IO Status
}
Y sus funciones pueden construir o consumir esta estructura de datos:
deployAllSensors :: ShuttleInterface -> IO ()
deployAllSensors shuttle = do
status <- getStatus shuttle
let notDeployed = filter (not . deployed) (sensors status)
when (isOrbiting status) (mapM_ deploySensor notDeployed)
-- we used the well-known Haskell functions: filter, not, , when, mapM_
-- and some supporting functions were assumed:
isOrbitting :: Status -> Bool
deploySensor :: Sensor -> IO ()
sensors :: Status -> [Sensor]
deployed :: Sensor -> Bool
¿Cómo se restringe el acceso a los datos en Haskell?
Para proporcionar abstracción, Haskell usa tipos de datos algebraicos . Para proteger los campos, los desarrolladores declaran un tipo de datos pero no exportan sus constructores; en su lugar, solo exportan un conjunto de primitivas seguras que mantienen las invariantes deseadas.
Por ejemplo, el módulo Map proporciona un árbol equilibrado. No podría garantizar el equilibrio si alguien pudiera simplemente declarar un Mapa utilizando las primitivas de Branch
y Leaf
, para que los fabricantes no las exporten. La construcción de un mapa debe basarse en lo que se exporta desde Data.Map (y aquellos que tienen acceso a / usan los constructores en virtud de estar en el mismo módulo) como fromList
, empty
, singleton
y un montón de modificadores.