2012-01-08 6 views
14

Я хотел бы реализовать следующий сценарий в Haskell. У меня есть счетного множества «событий» определен следующим образом:Обработка событий в Haskell

data MyEvent = Event1 
      | Event2 
      | Event3 

Я хочу, чтобы определить обработчик для этих событий, которые будут использоваться следующим образом:

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

В основном я хочу Обработчиков быть в состоянии вернуть себя или другого обработчика в обрабатывать будущие события. Это тип обработчиков, о которых я не уверен.

Моя первая идея состояла в том, чтобы определить обработчики как простые функции, но их тип будет получить бесконечно долго:

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

Я подозреваю, что это может быть решена с классом типа, где каждый обработчик нужно будет реализовать функция для обработки событий (которая, в свою очередь, возвращает другой тип того же класса), но рекурсивное определение все равно будет применяться. Может ли кто-нибудь еще лучше разбираться в системе типа, указывайте меня в правильном направлении? Я также приветствую любое другое взятие на этом.

Спасибо!

+0

Я думаю, что MyHandler :: [Событие] -> [IO()] 'и' eventLoop :: ([Event] -> [IO()]) -> IO() 'может быть лучшим подходом. – RnMss

ответ

17

Ну, «бесконечные» типы обычно представляют собой развернутые рекурсивные типы. Так что одна вещь, которую вы могли бы сделать, это сделать рекурсию явным использованием newtype:

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

Это также, вероятно, самое простое решение, потому что избавляет от необходимости жонглировать классы типов и различные экземпляры для того, чтобы получить различные behaviors-- каждый обработчик может выбрать то, что он возвращает, поскольку они имеют единый интерфейс.

Обратите внимание, что во многих случаях определение класса типа для решения такого рода проблем является излишним. Если вы имеете дело с полиморфным типом Handler h => h, все, что вы можете сделать с этим типом, это использовать функции класса класса. Если функции, определенные в этом типе, просты, вы можете сэкономить много хлопот, концептуально «предварительно применив» их.