[Haskell-cafe] Writing a generic event handler
John Ky
newhoggy at gmail.com
Wed Feb 11 18:17:41 EST 2009
Hi Haskell Cafe,
I'm interested in writing some events and event handlers in Haskell. I
already have a Loop data structure, and I intend to use it for this purpose:
-- Create event
tEvent <- newLoop (return ())
-- Register event handlers
tHandler1 <- newLoop (putStrLn "Handler1")
tHandler2 <- newLoop (putStrLn "Handler2")
splice tEvent tHandler1
splice tEvent tHandler2
-- Fire event
action <- doLoop tEvent
action
doLoop :: Monad m => TVar (Loop (m ())) -> STM (m ())
doLoop tLoop = do
aLoop <- readAsList tLoop
return $ sequence_ aLoop
My question is: Is it possible to write a generic doLoop that works over
arbitrary functions?
For instance the following code wouldn't work because the event provides one
argument and the handler takes one argument:
-- Create event
tEvent <- newLoop (\x -> return ())
-- Register event handlers
tHandler1 <- newLoop (\x -> putStrLn ("Handler1" ++ show x))
tHandler2 <- newLoop (\x -> putStrLn ("Handler2" ++ show x))
splice tEvent tHandler1
splice tEvent tHandler2
-- Fire event
action <- doLoop tEvent
action 123
Thanks,
-John
Full source code for Loop type:
module Fx.STM.Loop where
import Control.Monad
import Fx.STM.Util
import GHC.Conc
import System.IO.Unsafe
-- Transactional loop. A loop is a circular link list.
data Loop a
= ItemLink
{ item :: a
, prev :: TVar (Loop a)
, next :: TVar (Loop a)
}
-- Create a new empty transactional loop.
newLoop :: a -> STM (TVar (Loop a))
newLoop item = do
tLoop <- newTVar undefined
writeTVar tLoop (ItemLink item tLoop tLoop)
return tLoop
-- Splice two transactional loops. This will join two loops if they were
-- originally separate, or split a single loop if the links were originally
-- part of the same loop. No change occurs if the two links are identical.
splice :: TVar (Loop a) -> TVar (Loop a) -> STM ()
splice tLink0 tLink1 = do
aLink0 <- readTVar tLink0
aLink1 <- readTVar tLink1
let tLink0Prev = prev aLink0
let tLink1Prev = prev aLink1
writeTVar tLink0 aLink0 { prev = tLink1Prev }
writeTVar tLink1 aLink1 { prev = tLink0Prev }
aLink0Prev <- readTVar tLink0Prev
aLink1Prev <- readTVar tLink1Prev
writeTVar tLink0Prev aLink0Prev { next = tLink1 }
writeTVar tLink1Prev aLink1Prev { next = tLink0 }
return ()
-- Unlink a single link from a transactional loop.
unlink :: TVar (Loop a) -> STM ()
unlink tLink = do
(ItemLink item tLinkPrev tLinkNext) <- readTVar tLink
aLinkPrev <- readTVar tLinkPrev
writeTVar tLinkPrev aLinkPrev { next = tLinkNext }
aLinkNext <- readTVar tLinkNext
writeTVar tLinkNext aLinkNext { prev = tLinkPrev }
writeTVar tLink (ItemLink item tLink tLink)
return ()
-- Read the length of the loop.
readLength :: TVar (Loop a) -> STM Int
readLength tLink = do
list <- readAsList tLink
return $ length list
readLinks :: TVar (Loop a) -> STM [TVar (Loop a)]
readLinks tLink = readLinksUntil tLink tLink
readLinksUntil :: TVar (Loop a) -> TVar (Loop a) -> STM [TVar (Loop a)]
readLinksUntil tLink tLinkEnd = do
(ItemLink _ tLinkPrev tLinkNext) <- readTVar tLink
return []
if tLinkNext == tLinkEnd
then return [tLink]
else do
tail <- readLinksUntil tLinkNext tLinkEnd
return $ tLink:tail
-- Read the elements of the loop as a list starting from tLink.
readAsList :: TVar (Loop a) -> STM [a]
readAsList tLink = readAsListUntil tLink tLink
-- Read the elements of the loop as a list starting from tLink
-- and terminating non-inclusively at tLinkEnd.
readAsListUntil :: TVar (Loop a) -> TVar (Loop a) -> STM [a]
readAsListUntil tLink tLinkEnd = do
(ItemLink item tLinkPrev tLinkNext) <- readTVar tLink
if tLinkNext == tLinkEnd
then return [item]
else do
tail <- readAsListUntil tLinkNext tLinkEnd
return $ item:tail
-- Create a new loop from a list.
newFromList :: [a] -> STM (TVar (Loop a))
newFromList [item] = newLoop item
newFromList (item:items) = do
tLink <- newLoop item
tLinkRest <- newFromList items
splice tLink tLinkRest
return tLink
doLoop :: Monad m => TVar (Loop (m ())) -> STM (m ())
doLoop tLoop = do
aLoop <- readAsList tLoop
return $ sequence_ aLoop
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.haskell.org/pipermail/haskell-cafe/attachments/20090212/9e772326/attachment.htm
More information about the Haskell-Cafe
mailing list