2012-01-08 14 views
14

Vorrei implementare il seguente scenario in Haskell. Ho un enumerabile serie di 'eventi' definiti in questo modo:Gestione degli eventi in Haskell

data MyEvent = Event1 
      | Event2 
      | Event3 

voglio definire i gestori per questi eventi da utilizzare nel seguente modo:

eventLoop :: Handler h => h -> IO() 
eventLoop currentHandler = do 
    event <- getNextEvent 
    nextHandler <- currentHandler event 
    eventLoop nextHandler 

Fondamentalmente voglio gestori di essere in grado di restituire se stessi o un altro gestore a gestire gli eventi futuri. È il tipo di gestore di cui non sono sicuro.

La mia prima idea era quella di definire i gestori di come funzioni semplici, ma il loro tipo sarebbe ottenere infinitamente lungo:

myHandler :: Event -> IO (Event -> IO (Event -> ...)) 

ho il sospetto che questo può essere risolto con una classe tipo, in cui ogni gestore avrebbe bisogno implementare una funzione per gestire gli eventi (che a sua volta restituisce un altro tipo di della stessa classe), ma la definizione ricorsiva si applicherebbe comunque. Può qualcuno più esperto nel sistema di tipi indicarmi la giusta direzione? Inoltre, accolgo con favore ogni diversa interpretazione.

Grazie!

+0

Penso che 'MyHandler :: [Event] -> [IO()]' e 'eventLoop :: ([Event] -> [IO()]) -> IO()' potrebbe essere un approccio migliore. – RnMss

risposta

17

Bene, i tipi "infiniti" di solito corrispondono a tipi ricorsivi srotolati. Così una cosa che si potrebbe fare è rendere la ricorsione esplicito utilizzando un newtype:

newtype Handler = Handler { runHandler :: Event -> IO Handler } 

Questa è anche probabilmente la soluzione più semplice, perché evita la necessità di destreggiarsi tra le classi di tipo e diverse istanze al fine di ottenere behaviors-- diverso ogni handler può scegliere cosa restituire, poiché ha un'interfaccia uniforme.

Si noti che, in molti casi, la definizione di una classe di tipo per risolvere questo tipo di problema è del tutto superflua. Se hai a che fare con un tipo polimorfico Handler h => h, tutto ciò che puoi fare con quel tipo è usare le funzioni della classe del tipo su di esso. Se le funzioni definite su quella classe di caratteri sono semplici, puoi risparmiare un sacco di problemi concettualmente "pre-applicandoli".

Problemi correlati