leí William Cook "En Abstracción de datos, Revisited", y volver a leer Ralf Laemmel de "La expresión lema" para tratar de comprender cómo aplicar las ideas de la antigua de papel en Haskell. Entonces, estoy tratando de entender cómo podría implementar, por ejemplo, una función de unión establecida, en Haskell sin especificar los tipos.¿Cómo se declara un tipo de contenedor de datos abstracto en Haskell?
Respuesta
Hay múltiples maneras, dependiendo de la versión de "tipos de datos abstractos" que está buscando.
tipos de hormigón, pero opacos: Ha pasado un tiempo desde que leí el papel precioso de Cook, pero mirando hacia atrás sobre ella Creo que esto es más parecido a lo que está hablando como los ADT. La forma estándar de hacer esto en Haskell es exportar un tipo sin sus constructores; lo que esto significa en Haskell:
Sin patrón de coincidencia en los valores del tipo abstracto
No hay valores de la construcción del tipo, excepto el uso de las funciones exportadas de su módulo
Cómo esto se relaciona con el documento de Cook:
Independencia de representación: Desde el exterior, la representación es inaccesible.
Inspección de varias representaciones: Dentro del módulo de ADT, las representaciones se pueden inspeccionar libremente.
Implementaciones/módulos únicos: Diferentes implementaciones pueden ser proporcionadas por diferentes módulos, pero los tipos no pueden interoperar excepto por medios normales. No puede usar
Data.IntMap.null
para ver siData.Map.Map Int a
está vacío.
Esta técnica se usa ampliamente en las bibliotecas estándar Haskell, en particular para los tipos de datos que necesitan para mantener algún tipo de invariante o de otra manera restringir la capacidad de construir valores. Así pues, en este caso, la mejor manera de poner en práctica el ADT conjunto del artículo es el siguiente código:
import qualified Data.Set as S
Aunque esto es quizás no tan poderoso medio de la abstracción como podría ser en un idioma con una más expresiva sistema de módulos.
cuantificación existencial y la interfaz: Haskell no tiene realmente una palabra clave
exists
como tal, pero el término "existencial" se utiliza en diversas circunstancias para describir ciertos tipos de tipos polimórficos. La idea general en cada caso es combinar un valor con una colección de funciones que operan en él, de modo que el resultado sea polimórfico en el tipo del valor.Considere esta función firma:foo :: (a, a -> Bool) -> Bool
A pesar de que recibe un valor de tipo
a
, porquea
es totalmente polimórfico la única cosa que posiblemente puede hacer con ese valor es aplicar la función a ella. Entonces, en cierto sentido, dentro de esta función, la primera mitad de la tupla es un "tipo de datos abstracto", mientras que la segunda mitad es una "interfaz" para trabajar con ese tipo. Podemos hacer que esta idea explícita, y aplicarlo fuera de una sola función, usando un tipo de datos existencial:data FooADT = forall a. FooADT a (a -> Bool) foo :: FooADT -> Bool
Ahora, cada vez que tenemos un valor de tipo
FooADT
, todo lo que sabemos es que existe algún tipoa
de modo que podamos aplicar el segundo argumento deFooADT
al primero.La misma idea se aplica a los tipos polimórficos con restricciones de clase; la única diferencia es que las funciones que operan en el tipo son provistas implícitamente por la clase de tipo, en lugar de ser incluidas explícitamente con el valor.
Ahora, ¿qué significa esto en términos del artículo de Cook?
independencia Representación sigue siendo válida.
Aislamiento total: A diferencia de antes, el conocimiento del tipo cuantificado existencialmente se pierde para siempre. Nada puede inspeccionar la representación excepto la interfaz que proporciona.
Implementaciones arbitrarias: No solo las implementaciones no son necesariamente únicas, ¡no hay forma de limitarlas en absoluto! Cualquier cosa que pueda proporcionar la misma interfaz puede envolverse dentro de un elemento existencial y ser indistinguible de otros valores.
En resumen, esto es muy similar a la descripción de objetos de Cook. Para obtener más información sobre los ADT existenciales, el documento Unfolding Abstract Datatypes no es un mal lugar para comenzar; pero tenga en cuenta que lo que discute no es fundamentalmente lo que Cook llama un ADT.
Y un corto adición: Después de haber ido a todos los problemas anteriormente para describir las abstracciones de tipo existencial, me gustaría destacar algo sobre el tipo FooADT
: Porque todo lo que puede hacer con él es aplicar el función para obtener un resultado Bool
, no hay diferencia entre entre FooADT
y Bool
, excepto que el primero ofusca su código y requiere extensiones de GHC. Recomiendo encarecidamente reading this blog post antes de establecer el uso de tipos existenciales en el código Haskell.
Gracias, camccann, fue una respuesta excelente: exhaustiva, perspicaz y estimulante. (Como nota aparte, he leído esa entrada en el blog de luqui al menos tres veces ... todavía estoy tratando de que se hunda). – BMeph
Usted puede requerir una función de comparación que debe facilitarse o requerir los tipos a haber casos de la ecuación. Ver nub
y nubBy
para ejemplos de esta técnica:
nub :: (Eq a) => [a] -> [a]
nubBy :: (a -> a -> Bool) -> [a] -> [a]
- 1. ¿Cómo se declara el tipo de una preferencia de Android?
- 2. Listas en Haskell: tipo de datos o tipo de datos abstractos?
- 3. "No se puede asignar un objeto de tipo abstracto" error
- 4. Tipo abstracto devuelto en la clase base
- 5. Haskell dinámica de tipo de datos alteración
- 6. tipo vs rendimiento de datos en haskell
- 7. Haskell Aleatorio de tipo de datos
- 8. lista de doble enlace C con tipo de datos abstracto
- 9. Tipo de esquema abstracto desconocido
- 10. Java: tipo de retorno polimórfico en un método abstracto?
- 11. Clases concretas con miembros de tipo abstracto
- 12. Compruebe si los objetos tipo heredan un tipo abstracto
- 13. Tipo de datos de vocales en Haskell, ¿es posible?
- 14. Tipo abstracto de Scala que representa el tipo de subclase
- 15. Comprobaciones de entrada en los constructores de datos Haskell
- 16. Haskell gráfico de tipo de datos de representación
- 17. Haskell - especificando tipo en la declaración de datos
- 18. ¿Cómo puedo determinar el tamaño de un tipo en Haskell?
- 19. ¿Dónde se declara cout?
- 20. ¿Cómo descomprimir un tipo existencial haskell?
- 21. ¿Cómo puedo obtener un Singleton derivado de un tipo base abstracto en Java?
- 22. Cómo obtener datos en un contenedor de histogramas
- 23. ¿Por qué un delegado de .NET no se declara estático?
- 24. ¿Cómo escuchar un método abstracto?
- 25. Haskell Aeson: ¿Cómo convertir el valor en un tipo personalizado?
- 26. ¿Cómo obtener hijos de un contenedor WPF por tipo?
- 27. C# declara la subclase como tipo superclase
- 28. ¿Cómo se usa la clase de tipo delimitada en Haskell para definir un tipo con un rango de coma flotante?
- 29. Haciendo un tipo de datos de una instancia de Show en Haskell
- 30. miembros de Acceso de un tipo de datos personalizado en Haskell
Vía las clases de tipo, lo que le permite crear una plantilla de la función y sustituirla tanto en tipos de datos como en funciones? –