gameLost and gameWon just open message windows to tell you that you've lost or won. The smiley also takes appropriate action, feeling very sick or grinning inanely.
The windows are modal, so only after you closed them, the game is really over and can be started again.
The play event changes into gameOver once the game is over. It only lets you restart the game, and just swallows any of the button events (leCl etc). If we didn't react to the button events like that, they would still be in the event queue, and be reacted to once the game restarts-- not what you want really!
Anyway, now we have set up the logic to play the game we can spawn an event handler which waits for the game to start by synchronising on the start event. All that is left is to return the buttons so the main function can pack them. (Note that we bound events to buttons before packing them, this is entirely possible.)
This is the end of the buttons function. Everything else is just plain haskell. Ok, you're right, there is some tiny bits left. Nobody explained how the numbers show up when a non-mine field is explored, right? Okay, we'll come to that now.