2011-12-26 9 views
5

Właśnie natknąłem się na "nieskończony typ" w Haskell, kiedy próbowałem napisać skończoną maszynę stanów. Myślałem, że następuje bardzo intuicyjny:Nieskończone typy Haskella i moja funkcja 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 

daję funkcja State aktualny stan (akumulator) i nowe zdarzenie, a funkcja stan produkuje następną funkcję państwowej wraz z nowym akumulatorem. Powtarzam, dopóki nie będę miał więcej wydarzeń.

Kompilator mówi mi:

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

Ponieważ state jest teraz typ nieskończona. Jak mogę zmienić to, aby działało?

Odpowiedz

8

Nieskończone typy, takie jak ta, sieją spustoszenie w systemie typu; nie powodują, że jest to niebezpieczne, ale powodują one wiele programów do wpisania, których tak naprawdę nie chcemy, a co za tym idzie ukrywanie błędów, i uważam, że one również bardziej utrudniają wnioskowanie typu.

Na szczęście rozwiązanie jest proste: wystarczy utworzyć opakowanie jednostkowe newtype. Deklaracje data i newtype mogą oczywiście być rekurencyjne (w przeciwnym razie nie moglibyśmy nawet zdefiniować list!); to po prostu nieopakowane typy, które nie są.

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

Dzięki. Dla mnie wszystko to nadaje nieskończonemu typowi nazwę, ale sam typ wciąż sam się odwołuje. Sam kompilator nazwał nawet nieskończony typ. Pomyślałem, że kompilator będzie mógł zautomatyzować to, nadając mu nazwę. Czy się mylę? – Ana

+5

@Ana: Chociaż prawdą jest, że Haskell uważa, że ​​twój program jest nieważny przez * wybór *, a nie konieczność, to z bardzo dobrego powodu; Nie mam teraz żadnych linków, ale * wiele * często popełnianych błędów, które polegają na systemie typów do sprawdzenia - np. Brakujące argumenty lub dwukrotne wpisanie nazwy funkcji - stają się ważnymi programami (ale zepsutymi), jeśli pozwolisz na nieskończone typy. – ehird

+3

Należy zauważyć, że nie jest to tak proste, jak podanie nazwy typu: 'type Infinite = (Bool, Infinite)' jest również zbanowany; musisz zawinąć go w * typ danych *, który omija wszystkie możliwości błędów, ponieważ musisz jawnie skonstruować i dopasować do wzorca (lub użyć funkcji akcesora). – ehird

Powiązane problemy