Me gustaría aprender a hacer gráficos y realizar algunas operaciones locales en Haskell, pero la pregunta no es específica de Haskell, y en lugar de gráficos podemos considerar listas doblemente vinculadas.
Pregunta: ¿Cuál sería una forma idiomática o recomendada de implementar una lista doblemente enlazada (u otra estructura de datos doblemente enlazada o circular) y operaciones en un lenguaje que apoye y defienda principalmente estructuras de datos inmutables (Haskell, Clojure, etc.) ? En particular, ¿cómo usar las actualizaciones en el lugar, que están formalmente prohibidas por el idioma?
Puedo imaginar fácilmente que si se realiza alguna operación local en una lista doblemente vinculada (si se inserta un elemento, por ejemplo), puede que no sea necesario copiar toda la lista inmediatamente debido a la flojera del idioma. Sin embargo, dado que la lista está doblemente vinculada, si se modifica en un lugar, ninguno de los nodos antiguos se puede usar en la nueva versión de la lista, y necesitarían ser marcados, copiados, recolectados de basura de alguna manera tarde o temprano. . Obviamente, estas son operaciones redundantes si solo se utilizara la copia actualizada de la lista, pero agregarían una "sobrecarga" proporcional al tamaño de la lista.
¿Significa esto que para esas tareas los datos inmutables son simplemente inapropiados y que los lenguajes declarativos funcionales sin soporte "nativo" para datos mutables no son tan buenos como los imperativos? O, ¿hay alguna solución difícil?
PD: He encontrado algunos artículos y presentaciones sobre este tema en Internet, pero tuve dificultades para seguirlos, aunque creo que la respuesta a esta pregunta no debería tomar más de un párrafo y tal vez un diagrama ... Quiero decir, si hay no hay una solución "funcional" para este problema, la respuesta probablemente sea "usar C". Si hay uno, entonces, ¿qué tan complicado puede ser?
Preguntas relacionadas
"Estructuras de datos en programación funcional" . Mi pregunta específica sobre el uso de actualizaciones en el lugar en lugar de alternativas ineficientes no se discute allí.
"Mutación interna de estructuras de datos persistentes" . Allí el énfasis parece estar en la implementación de bajo nivel en un lenguaje no especificado, mientras que mi pregunta es sobre la elección correcta de un idioma (funcional o no) y sobre posibles soluciones idiomáticas en lenguajes funcionales.
Citas relevantes
Los lenguajes de programación puramente funcionales permiten que muchos algoritmos se expresen de manera muy concisa, pero hay algunos algoritmos en los que el estado actualizable en el lugar parece desempeñar un papel crucial. Para estos algoritmos, los lenguajes puramente funcionales, que carecen de estado actualizable, parecen ser inherentemente ineficientes ( [Ponder, McGeer y Ng, 1988] ).
- John Launchbury y Simon Peyton Jones, Hilos de estado funcional perezoso (1994), también John Launchbury y Simon Peyton Jones, Estado en Haskell (1995). Estos documentos introducen el ST
constructor de tipo monádico en Haskell.
DiffArray
tipo. Mirando la fuente del paquete diffarray , veo 91 ocurrencias de unsafePerformIO
. Parece que la respuesta a mi pregunta es "sí, no, los lenguajes puramente funcionales con datos inmutables no son apropiados para implementar algoritmos que normalmente dependen de actualizaciones en el lugar".
Map
, IntMap
o HashMap
) como un almacenamiento y para hacer nodos contienen identificadores de los nodos vinculados. "Todos los problemas en informática pueden resolverse mediante otro nivel de indirección".