2012-01-08 1 views
14

Me gustaría implementar la siguiente situación en Haskell. Tengo una conjunto numerable de 'eventos' se definen así:Manejo de eventos en Haskell

data MyEvent = Event1 
      | Event2 
      | Event3 

quiero definir manejadores de estos eventos que se utilizarán de la siguiente manera:

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

Básicamente quiero manipuladores sean capaz de devolver ellos mismos u otro controlador al manejar futuros eventos. Es el tipo de manejadores del que no estoy seguro.

Mi primera idea era definir manipuladores como funciones simples, pero su tipo sería obtener infinitamente largo:

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

Sospecho que esto se puede resolver con un tipo de clase, donde cada controlador necesitaría para implementar una función para manejar eventos (que a su vez devuelve otro tipo de la misma clase), pero la definición recursiva aún se aplicaría. ¿Puede alguien más versado en el sistema de tipo señalarme en la dirección correcta? También bienvenida cualquier toma diferente en esto.

Gracias!

+0

Creo que 'MyHandler :: [Event] -> [IO()]' y 'eventLoop :: ([Event] -> [IO()]) -> IO()' podría ser un mejor enfoque. – RnMss

Respuesta

17

Bueno, los tipos "infinitos" generalmente equivalen a tipos recursivos desenrollados. Así que una cosa que podría hacer es hacer la recursión explícita mediante un newtype:

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

Ésta es también, probablemente, la solución más sencilla, ya que evita la necesidad de hacer malabares clases de tipos y diferentes instancias con el fin de obtener diferentes behaviors-- cada controlador puede elegir lo que devuelve, ya que tienen una interfaz uniforme.

Tenga en cuenta que, en muchos casos, definir una clase de tipo para resolver este tipo de problema es completamente superfluo. Si está tratando con un tipo polimórfico Handler h => h, todo lo que puede hacer con ese tipo es usar las funciones de la clase de tipo en él. Si las funciones definidas en esa clase de tipo son simples, puede ahorrarse muchas molestias conceptualmente "preaplicándolas".

Cuestiones relacionadas