A simple message-handling loop. Listeners can watch for/react to multiple types of messages and multiple listeners can react to the same message, although order of processing is not guaranteed.
I'm currently using this in a GUI system to simplify interdependencies and multi-step data gathering -- instead of getting lost in callback hell where various controls and/or processing can block the GUI thread, I simply post a message and move on. It makes things a lot simpler.
#lang racket
(require message-loop)
(start-message-loop)
(add-listeners
(listener++ #:listen-for '(matriculate)
#:action (lambda (lstnr msg)
(match-define (cons name school) (message-data msg))
(displayln (format "~a got into ~a" name school))))
(listener++ #:listen-for '(birthday wedding)
#:id 'life-event-listener-1
#:action (lambda (lstnr msg)
(displayln (format "listener id: '~a' heard that there was a ~a"
(listener-id lstnr)
(message-type msg)))))
(listener++ #:listen-for '(birthday wedding)
#:id 'life-event-listener-2
#:action (lambda (lstnr msg)
(displayln (format "listener id: '~a' heard that there was a ~a"
(listener-id lstnr)
(message-type msg))))))
(post-message (message++ #:type 'matriculate #:data (cons 'alice "Northwestern")))
(post-message (message++ #:type 'graduate #:data (cons 'bob "Northwestern")))
(post-message 'birthday)
(post-message 'wedding)
; output is:
;
; alice got into Northwestern
; listener id: 'life-event-listener-1' heard that there was a birthday
; listener id: 'life-event-listener-2' heard that there was a birthday
; listener id: 'life-event-listener-1' heard that there was a wedding
; listener id: 'life-event-listener-2' heard that there was a wedding
; NB: Order of processing is not guaranteed for the 'life-event-listener-N' messages