2012-03-27 12 views
24

Eventuali duplicati:
How to tell if a list is infinite?Riesci a riconoscere una lista infinita in un programma Haskell?

In Haskell, è possibile definire una lista infinita, per esempio [1..]. Esiste una funzione incorporata in Haskell per riconoscere se una lista ha una lunghezza finita? Non immagino che sia possibile scrivere una funzione fornita dall'utente per farlo, ma la rappresentazione interna degli elenchi di Haskell potrebbe essere in grado di supportarla. Se non in Haskell standard, esiste un'estensione che fornisce tale funzionalità?

+2

Non credo. A causa della valutazione lenta, il runtime di Haskell non sa davvero se la lista sarà infinita; non è che non lo esponga al programma. –

+12

Sospetto fortemente che questo sia equivalente al cosiddetto "problema di interruzione", nel qual caso la risposta sarebbe "No". –

+0

Se desideri essere in grado di riconoscere strutture infinite, puoi leggere qualcosa sulla coinduzione: http://en.wikipedia.org/wiki/Coinduction, http://www.disi.unige.it/dottorato/corsi/DPCI2011/ –

risposta

39

No, questo non è possibile. Sarebbe impossibile scrivere una funzione del genere, perché si possono avere liste la cui finitezza potrebbe essere sconosciuta: si consideri un ciclo ricorsivo che genera un elenco di tutti gli twin primes che può trovare. Oppure, per dare un seguito a ciò che Daniel Pratt ha menzionato nei commenti, si può avere un elenco di tutti i passaggi che uno universal Turing machine prende durante l'esecuzione, terminando l'elenco quando la macchina si ferma. Quindi, puoi semplicemente controllare se un elenco di questo tipo è infinito e risolvere lo Halting problem!

L'unica domanda un'implementazione potrebbe essere risposta è se un elenco è ciclico: se uno dei suoi puntatori di coda punta indietro a una cella precedente della lista. Tuttavia, questo è specifico dell'implementazione (Haskell non specifica nulla su come le implementazioni devono rappresentare i valori), impuro (diversi modi di scrivere la stessa lista darebbe risposte diverse), e anche dipendente da cose come se la lista che si passa a tale funzione è stata ancora valutata. Anche allora, non sarebbe ancora in grado di distinguere le liste finite da liste infinite nel caso generale!

(Dico questo perché, in molte lingue (come membri della famiglia Lisp), liste ciclici sono il unico tipo di liste infinite, non c'è modo per esprimere qualcosa di simile a "un elenco di tutti i numeri interi". così, in tali lingue, si può verificare se una lista è finita o meno.)

+3

Per controllare se un elenco è ciclico, controlla [vuoto] (http://hackage.haskell.org/package/vacuum), che può restituire un grafico del layout heap di un valore Haskell che è possibile controllare per cicli. Tuttavia, questo è sia specifico per il GHC che impuro come sopra indicato. – hammar

+0

La (in) finitudine dei gemelli primi non è nota per essere indecidibile; finora, rispondere alla domanda è davvero, davvero, davvero, davvero difficile. – jwodder

+0

@jwodder: Sì, era un pessimo fraseggio. Ho modificato la mia risposta. – ehird

6

non c'è alcun modo per testare per la finitezza delle liste diverse da iterare su l'elenco per cercare la finale [] in qualsiasi implementazione di cui sono a conoscenza. E in generale, è impossibile dire se una lista è finita o infinita senza effettivamente andare a cercare la fine (che ovviamente significa che ogni volta che si ottiene una risposta, che dice finito).

6

si potrebbe scrivere un tipo di wrapper lista che tiene traccia delle infinitezza, e ci si limita alle operazioni di "decidibili" solo (in qualche modo simili a NonEmpty, che evita liste vuote):

import Control.Applicative 

data List a = List (Maybe Int) [a] 

infiniteList (List Nothing _) = true 
infiniteList _ = false 

emptyList = List (Just 0) [] 
singletonList x = List (Just 1) [x] 
cycleList xs = List Nothing (cycle xs) 
numbersFromList n = List Nothing [n..] 
appendList (List sx xs) (List sy ys) = List ((+) <$> sx <*> sy) (xs ++ ys) 
tailList (List s xs) = List (fmap pred s) (tail xs) 
... 
+0

Qual è il vantaggio di archiviare effettivamente la lunghezza, non farebbe un semplice 'Bool'? Dopotutto, per una lista finita è ridondante. – leftaroundabout

+1

Anche 'Bool' farebbe lo stesso, ma fondamentalmente vogliamo essere in grado di scoprire" quanto tempo "è la nostra lista, quindi perché non sfruttare l'argomento addizionale, specialmente perché' length' è lento per le lunghe liste? – Landei

1

Quando si parla di "rappresentazione interna delle liste", dal punto di vista dell'implementazione di Haskell, non ci sono liste infinite. La "lista" che chiedi è in realtà una descrizione del processo computazionale, non un oggetto dati. Nessun oggetto dati è infinito all'interno di un computer. Una cosa del genere semplicemente non esiste.

Come altri hanno già detto, i dati interni dell'elenco potrebbero essere ciclici e l'implementazione di solito sarebbe in grado di rilevare questo, avendo un concetto di uguaglianza dei puntatori. Ma Haskell non ha questo concetto.

Ecco una funzione Common Lisp per rilevare la ciclicità di un elenco. cdr anticipi lungo una lista di una tacca e cddr - di due. eq è un predicato di uguaglianza puntatore.

(defun is-cyclical (p) 
    (labels ((go (p q) 
      (if (not (null q)) 
       (if (eq p q) t 
       (go (cdr p) (cddr q)))))) 
    (go p (cdr p)))) 
Problemi correlati