2015-05-16 12 views
19

In Haskell, alcune liste sono ciclici:La capacità di rilevare elenchi ciclici in Haskell interromperà qualsiasi proprietà della lingua?

ones = 1 : ones 

Altri non sono:

nums = [1..] 

E poi ci sono cose come questa:

more_ones = f 1 where f x = x : f x 

Questo indica lo stesso valore di ones e certamente quel valore è una sequenza ripetitiva. Ma se è rappresentato in memoria come una struttura ciclica dei dati è dubbia. (Un'implementazione potrebbe farlo, ma this answer explains that "it's unlikely that this will happen in practice".)

Supponiamo prendiamo un'implementazione Haskell e incidere in esso una funzione isCycle :: [a] -> Bool incorporata che esamina la struttura della rappresentazione in memoria dell'argomento. Restituisce True se l'elenco è fisicamente ciclico e False se l'argomento è di lunghezza finita. Altrimenti, non riuscirà a terminare. (Immagino "hacking in" perché è impossibile scrivere quella funzione in Haskell.)

Sarebbe l'esistenza di questa funzione rompere le interessanti proprietà del linguaggio?

+12

Bene, all'improvviso è possibile restituire valori diversi per gli stessi input: 'f x = se isCycle x then 1 else 2'. Ciò restituire '1' o' 2' per il valore 'ones' a seconda di come si costruisce quella stessa lista. Ciò sembra piuttosto grave se si considera che uno dei vantaggi più evidenti dei linguaggi funzionali è che una funzione restituirà sempre lo stesso risultato se gli stessi valori sono immessi in input ... – Bakuriu

+5

Questo è sempre considerato accettabile quando vincolato a 'IO' . Puoi scrivere 'isCycle :: [a] -> IO Bool' in termini di una struttura esplicita del grafico di una lista ottenuta da [data-reify] (https://hackage.haskell.org/package/data-reify) che utilizza internamente ['StableName's] (http://hackage.haskell.org/packages/archive/base/latest/doc/html/System-Mem-StableName.html#t:StableName). Se guardi troppo in memoria con 'IO' puoi fare cose assolutamente malvagie, come [rompere la purezza delle funzioni pure senza ricorrere a qualcosa di non sicuro] (http://stackoverflow.com/a/28701687/414413). – Cirdec

+0

Controllare se un elenco è fisicamente ciclico richiederebbe di controllare tutti i nodi finché non viene trovato un ciclo. Questo non finirà sulla lista infinita in Haskell. Comunque sarà in Lisp (e probabilmente in tutte le lingue imperative), perché la lista ciclica è l'unico modo per fare una lista infinita. – mb14

risposta

11

L'esistenza di questa funzione interromperà proprietà interessanti del linguaggio?

sarebbe. Si romperebbe referential transparency (vedere anche the Wikipedia article). Un'espressione Haskell può sempre essere sostituita dal suo valore. In altre parole, dipende solo dagli argomenti passati e nient'altro. Se avessimo

isCycle :: [a] -> Bool 

come lei propone, espressioni utilizzando non sarebbe soddisfare questa proprietà più. Potrebbero dipendere dalla rappresentazione della memoria interna dei valori. Di conseguenza, altre leggi sarebbero violate. Ad esempio, il identity law per Functor

fmap id === id 

non avrebbe retto più: Sareste in grado di distinguere tra ones e fmap id ones, in quanto quest'ultimo sarebbe aciclico. E le ottimizzazioni del compilatore come l'applicazione della legge sopra non preserverebbero più le proprietà del programma.

Tuttavia un'altra domanda sarebbe avere funzione

isCycleIO :: [a] -> IO Bool 

come IO azioni sono autorizzati a esaminare e cambiare qualcosa.

Una soluzione pura potrebbe essere quella di avere un tipo di dati che distingue internamente i due:

import qualified Data.Foldable as F 

data SmartList a = Cyclic [a] | Acyclic [a] 

instance Functor SmartList where 
    fmap f (Cyclic xs) = Cyclic (map f xs) 
    fmap f (Acyclic xs) = Acyclic (map f xs) 

instance F.Foldable SmartList where 
    foldr f z (Acyclic xs) = F.foldr f z xs 
    foldr f _ (Cyclic xs) = let r = F.foldr f r xs in r 

Naturalmente non sarebbe in grado di riconoscere se un elenco generico è ciclica o no, ma per molte operazioni sarebbe possibile conservare la conoscenza di avere valori Cyclic.

+0

Penso che tu intenda "fmap id ones", non "fmap ones". – amalloy

+0

@amalloy Sì, grazie, corretto. –

0

Nel caso generale, non è possibile identificare una lista ciclica. Tuttavia, se l'elenco viene generato da un'operazione di svolgimento, è possibile. Data.List contiene questo:

unfoldr :: (b -> Maybe (a, b)) -> b -> [a] 

Il primo argomento è una funzione che prende uno "stato" argomento di tipo "b" e può restituire un elemento della lista e un nuovo stato. Il secondo argomento è lo stato iniziale. "Niente" significa che la lista finisce.

Se lo stato si ripete, l'elenco si ripeterà dal punto dell'ultimo stato. Quindi, se invece usiamo una funzione di spiegatura diversa che restituisce una lista di coppie (a, b), possiamo esaminare lo stato corrispondente a ciascun elemento. Se lo stesso stato viene visto due volte, l'elenco è ciclico. Ovviamente questo presuppone che lo stato sia un'istanza di Eq o qualcosa del genere.

Problemi correlati