2011-12-26 13 views
5

Ho appena incontrato il "tipo infinito" in Haskell mentre stavo tentando di scrivere una macchina a stati finiti. Ho pensato che il seguente è stato molto intuitivo:Haskell infiniti tipi e la mia funzione FSM

fsm []  _  acc = Right acc 
fsm (x:xs) state acc = 
    case state acc x of 
     Left err  -> Left err 
     Right (s, a) -> fsm xs s a 

rendo la funzione di stato allo stato attuale (l'accumulatore) e il nuovo evento, e la funzione stato produce la funzione stato successivo insieme al nuovo accumulatore. Ricevo fino a quando non ho più eventi.

Il compilatore mi dice:

Occurs check: cannot construct the infinite type: 
    t1 = b0 -> t0 -> Either a0 (t1, b0) 
In the second argument of `fsm', namely `s' 

Perché state è ora un tipo di infinito. Come riorganizzare questo per farlo funzionare?

risposta

8

I tipi infiniti come questo causano il caos con il sistema di tipi; non lo rendono pericoloso, ma causano una grande quantità di programmi da digitare che in realtà non si desidera, nascondendo così gli errori, e credo che rendano anche più difficile l'inferenza di tipo.

Per fortuna, la soluzione è semplice: devi solo creare un wrapper newtype. Le dichiarazioni data e newtype sono ovviamente consentite per essere ricorsive (altrimenti, non potremmo nemmeno definire le liste!); sono tipi semplici, non confezionati che non lo sono.

newtype FSMState err acc ev = 
    FSMState { stepFSM :: acc -> ev -> Either err (FSMState err acc ev, acc) } 

fsm :: [ev] -> FSMState err acc ev -> acc -> Either err acc 
fsm []  _  acc = Right acc 
fsm (x:xs) state acc = 
    case stepFSM state acc x of 
     Left err  -> Left err 
     Right (s, a) -> fsm xs s a 
+0

Grazie. Per me, tutto ciò che fa è dare al tipo infinito un nome, ma il tipo stesso è ancora autoreferenziale. Lo stesso compilatore ha persino chiamato il tipo infinito allo stesso modo. Avrei pensato che il compilatore sarebbe stato in grado di automatizzarlo dandogli un nome. Mi sbaglio? – Ana

+5

@Ana: Mentre è vero che Haskell considera il tuo programma non valido per * scelta * e non per necessità, è per una buona ragione; Non ho alcun collegamento in questo momento, ma * molti * errori comuni su cui ci affidiamo al sistema di tipi da controllare - come mancare un argomento o scrivere un nome di funzione due volte - diventano programmi digitati in modo valido (ma spezzati) se permetti infiniti tipi. – ehird

+3

Nota che non è così semplice come dare un nome al tipo: 'type Infinite = (Bool, Infinite)' è anch'esso vietato; devi racchiuderlo in un * tipo di dati *, che elude tutte le possibilità di errori, perché devi costruire in modo esplicito e abbinare (o utilizzare le funzioni di accesso) su di esso. – ehird

Problemi correlati