Elenchi di differenze nella programmazione funzionale


13

La domanda Cosa c'è di nuovo nelle strutture di dati puramente funzionali da Okasaki? e l'epica risposta di jbapple, menzionata usando liste di differenze nella programmazione funzionale (al contrario della programmazione logica), che è qualcosa che mi ha interessato di recente. Questo mi ha portato a trovare l' implementazione delle liste di differenze per Haskell. Ho due domande (perdonami / correggimi se dovessi farle due domande diverse su StackExchange).

La semplice domanda è: qualcuno è a conoscenza della considerazione accademica degli elenchi delle differenze nella programmazione funzionale e / o implementazioni oltre a quella nella biblioteca di Haskell? La risposta di jbapple non ha fornito una citazione per gli elenchi delle differenze (gli elenchi delle differenze nella programmazione logica esistono nella tradizione e in un paio di fonti che ho Around Here Somewhere (TM)). Prima di trovare l'implementazione di Haskell non ero consapevole che l'idea fosse passata dalla logica alla programmazione funzionale. Certo, gli elenchi delle differenze di Haskell sono una sorta di uso naturale di funzioni di ordine superiore e funzionano in modo molto diverso da quelli della programmazione logica, ma l'interfaccia è sicuramente simile.

La cosa più interessante (e di gran lunga più sfacciata) che volevo chiedere è se il limite superiore asintotico dichiarato per la suddetta libreria dell'elenco delle differenze di Haskell sembra corretto / plausibile. La mia confusione potrebbe essere perché mi manca qualcosa di ovvio sul ragionamento della complessità con la pigrizia, ma i limiti dichiarati hanno senso per me solo se la sostituzione su una grande struttura di dati (o formazione di chiusura, o ricerca variabile o qualcosa ) richiede sempre tempo costante. O la "cattura" è semplicemente che non ci sono limiti al tempo di esecuzione di "testa" e "coda" proprio perché quelle operazioni potrebbero dover passare attraverso una pila arbitraria di calcoli / sostituzioni differite?


1
All'inizio ero confuso dai "linguaggi di programmazione funzionale (al contrario dei linguaggi di programmazione funzionale)", ma intendevi scrivere "(al contrario dei linguaggi di programmazione logica)"?
Tsuyoshi Ito,

Oh oops - sì, è quello che volevo dire, ora è stato risolto.
Rob Simmons,

La seconda domanda mi sembra più appropriata su StackTranslate.it, ma ora che l'hai posta qui, potrebbe essere meglio aspettare per vedere se qualcuno può rispondere qui. Personalmente non riesco a trovare alcun motivo per dubitare dei limiti dichiarati dalla lettura del codice sorgente, ma non ho seguito il tuo ragionamento per dubitarne, e potrei anche mancare qualcosa.
Tsuyoshi Ito,

Risposte:


8

O la "cattura" è semplicemente che non ci sono limiti al tempo di esecuzione di "testa" e "coda" proprio perché quelle operazioni potrebbero dover passare attraverso una pila arbitraria di calcoli / sostituzioni differite?

Θ(m)m

O(1) fromList

{-# LANGUAGE NoMonomorphismRestriction #-}

data DL a = Id
          | Cons a
          | Compose (DL a) (DL a)

fromList [] = Id
fromList (x:xs) = Compose (Cons x) (fromList xs)

toList x = help x []
    where help Id r = r
          help (Cons a) r = a:r
          help (Compose f g) r = help f $ help g r

empty = Id

singleton = Cons

cons x = append (singleton x)

append = Compose

snoc xs x = append xs (singleton x)

Θ(n)headtail[a] -> [a]toList


Quindi quello che stai ottenendo dalla pigrizia è solo che chiedere due volte la coda di una lista non farà due volte l'operazione costosa, il che è bello.
Rob Simmons,

@Rob, non capisco cosa intendi con questo.
jbapple,

Penso che il punto che stavo tentando di chiarire (malamente) sia illustrato da questo esempio: ho una lista di differenze straordinariamente lunga "xs" che ho fatto ripetutamente "accennando" alla lista originale. La prima volta che chiamo "head xs" mi aspetto che ci vorrà O (n) tempo per eseguire il calcolo differito; tuttavia, poiché tale calcolo dovrebbe essere memorizzato, la seconda chiamata a "head xs" (per la stessa "xs") dovrebbe richiedere O (1) tempo.
Rob Simmons,

1
Bene, sono d'accordo con questo, ma la pigrizia a cui ho fatto riferimento nella mia risposta riguardava FromList, che non è usato in Snoc o Head. Quindi, per quanto pedante sia, sono stato confuso dal "cosa" nella tua affermazione "cosa stai ottenendo dalla pigrizia". Direi che il tuo esempio e il mio sono due cose che ottieni dalla pigrizia.
jbapple,

Ok - e anche questo chiarimento mi aiuta a capire meglio il tuo punto precedente.
Rob Simmons,

11

Sì, i limiti dipendono dal presupposto che la composizione della funzione richiede tempo costante. Fondamentalmente, se si dispone di un elenco di join:

datatype 'a join = Nil | Cons of 'a * 'a join | Join of 'a join * 'a join

È ovvio che la concatenazione è un tempo costante e che lo è O(n)per trasformarlo in un contro-elenco. Se si pensa alla solita rappresentazione di chiusure, si può vedere che questa è sostanzialmente la stessa rappresentazione puntatore della solita rappresentazione di tipi di dati. (In alternativa, è possibile visualizzare questo tipo come un elenco di differenze defunzionalizzato.)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.