2012-02-16 11 views
9

Recently fui presentato a this OCaml code che a Haskell può essere scritta come:funzionale lista doppiamente collegata pura "True" e la condivisione di nodi

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" 

che mi era non una vera e propria lista doppiamente collegata implementazione, in quanto crea nuovo storage su attraversamento. OTOH c'è 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 

Possiamo dire che si tratta solo di questo codice che è vero dl-list?

Possiamo fare affidamento su questo codice per introdurre la vera condivisione dei nodi della lista dl, in modo che non venga creato alcun nuovo spazio di archiviazione durante la traversata?

è lo stesso nome variabile in Haskell sempre riferendosi al la stessa "cosa" o potrebbe separare le occorrenze dello stesso nome variabile riferimento alla copia separata della stessa cosa? (modificato per aggiungere enfasi).

+5

La prima implementazione è ciò che è noto come _Zipper_; probabilmente può essere per liste singole o doppie. Tuttavia, non è un'implementazione di lista a sé stante. – ivanm

+5

Se si legge attentamente il report Haskell, non è possibile trovare un singolo paragrafo sul modo in cui i dati sono rappresentati. Tieni presente che tutti i tipi di condivisione dipendono dall'implementazione, anche se per la maggior parte sono disponibili solo pochi modi per implementare determinate funzionalità. – fuz

+0

Grazie per questa domanda! Non sono soddisfatto con il mio, guardando per questo. – demi

risposta

3

Suggerirei che quest'ultimo è l'implementazione "corretta", sì.

Non ho i fatti con cui eseguire il backup, ma mi sembra, considerando la mia comprensione dell'implementazione di GHC, che quest'ultimo dovrebbe funzionare come ci si aspetterebbe che una lista a doppio collegamento funzioni.

+0

grazie! Mi piacerebbe avere certezze, specialmente riguardo alla mia ultima domanda. :) –

+1

@WillNess Credo che sia un problema di implementazione, ma GHC utilizza la rappresentazione basata su puntatore sotto il cofano per rappresentare la stessa cosa (ad esempio in 'xs ++ ys', il valore originale' ys' è usato come la fine di la nuova lista combinata). – ivanm

6

È possibile visualizzare l'aspetto del layout di memoria della struttura dati utilizzando un pacchetto chiamato vacuum-cairo. Installa da hackage con cabal install vacuum-cairo allora si dovrebbe essere in grado di verificare la differenza tra le due strutture da qualcosa di simile nel GHCi:

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

Vi si possono vedere i nodi sono condivisi con il dlist dove come DL è di due liste con un elemento intermedio (come sottolineato, questa è una specie di chiusura lampo).

Nota: questo è specifico per GHC, un'implementazione diversa potrebbe rappresentare i dati in memoria in modo diverso, ma ciò sarebbe tipico.

+0

grazie, capisco come * dovrebbe * essere. Ma è stato suggerito (nel post a cui si collega la prima parola nella mia domanda) che la condivisione non è garantita. Quindi, come dovrebbe essere la struttura, e come "cairo" me lo mostrerebbe, non sarà necessariamente come è nella realtà. Voglio sapere, c'è una garanzia che almeno la stessa named var punta sempre alla stessa cosa in memoria, in qualsiasi implementazione? –

+0

Sì, altrimenti un esempio come questo non funzionerà: '(x, xs) = let y = replica 10 x in (length y, y)' – Oliver

+0

Penso che funzionerebbe ancora, dato che non ci sono cicli nel flusso delle dipendenze nel tuo esempio. –