2012-02-16 14 views
9

Recently me presentaron a this OCaml code que, en Haskell se puede escribir como:lista funcional pura "Verdadero" doblemente enlazada y recursos compartidos de nodos

data DL a = DL [a] a [a] 

create [] = error "empty list" 
create (x:xs) = DL [] x xs 

next (DL pr x (h:tl)) = DL (x:pr) h tl 
next _ = error "end of dlist" 

prev (DL (p:pr) x tl) = DL pr p (x:tl) 
prev _ = error "start of dlist" 

la que yo estaba, aunque no una lista doblemente enlazada adecuada implementación, ya que crea un nuevo almacenamiento en el cruce. Otoh hay this Haskell code:

data DList a = Leaf | Node { prev::(DList a), elt::a, next::(DList a) } 

create = go Leaf 
    where go _ []  = Leaf 
     go prev (x:xs) = current 
      where current = Node prev x next 
        next = go current xs 

Podemos decir que es solamente el código eso es cierto dl-lista?

¿Podemos confiar en este código para introducir el intercambio real de los nodos de la lista dl, de modo que no se cree un nuevo almacenamiento en el recorrido?

¿Está el mismo nombre variable en Haskell haciendo siempre referencia a la misma "cosa" o podría separar las ocurrencias del mismo nombre variable de referencia a copia separada de la misma cosa? (editado para agregar énfasis).

+5

La primera implementación es lo que se conoce como _Zipper_; podría decirse que puede ser para listas vinculadas individualmente o doblemente. Sin embargo, no se trata de una implementación de listas por derecho propio. – ivanm

+5

Si lee el informe de Haskell con cuidado, no puede encontrar un solo párrafo sobre cómo se representan los datos. Tenga en cuenta que todo tipo de intercambio depende de la implementación, aunque en su mayoría solo existen algunas formas sensatas de implementar una determinada función. – fuz

+0

¡Gracias por esta pregunta! No he satisfecho con mi, esperando esto. – demi

Respuesta

3

Sugeriría que la última es la implementación "correcta", sí.

No tengo datos para respaldarlo, pero me parece, dado mi conocimiento de la implementación de GHC, que este último debería funcionar como se esperaría que funcionara una lista de doble enlace.

+0

gracias! Me gustaría tener certeza, especialmente sobre mi última pregunta. :) –

+1

@WillNess Creo que es un problema de implementación, pero GHC utiliza la representación basada en punteros para representar lo mismo (por ejemplo, en 'xs ++ ys', el valor' ys' original se utiliza como el final de la nueva lista combinada). – ivanm

6

Puede visualizar cómo se ve el diseño de la memoria de su estructura de datos utilizando un paquete llamado vacuum-cairo. Instala desde hackage con cabal install vacuum-cairo, entonces debería ser capaz de verificar la diferencia de las dos estructuras por algo como esto en GHCi:

> import System.Vacuum.Cairo 
> view $ create [1..5] 

Allí se puede ver los nodos son compartidos con el DList donde como DL es dos listas con un elemento intermedio (como se señaló, esto es una especie de Cremallera).

Nota: Esto es específico de GHC, una implementación diferente podría representar los datos en la memoria de manera diferente, pero esto sería típico.

+0

gracias, entiendo cómo * supuso * ser. Pero se sugirió (en la publicación a la que se vincula la primera palabra de mi pregunta) que compartir no está garantizado. Entonces, cómo se supone que debe ser la estructura, y cómo 'cairo' me lo mostrará, no será necesariamente lo que es en realidad. Quiero saber, ¿hay alguna garantía de que al menos la misma var nombrada siempre apunte a lo mismo en la memoria, en cualquier implementación? –

+0

Sí, de lo contrario un ejemplo como este no funcionará: '(x, xs) = let y = replica 10 x in (length y, y)' – Oliver

+0

Creo que todavía funcionaría, ya que no hay ciclos en el flujo de dependencia en tu ejemplo. –

Cuestiones relacionadas