Santa

From HaskellWiki
Revision as of 14:05, 25 June 2007 by ChrisKuklewicz (talk | contribs) (Add example code)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

ChrisKuklewicz 14:05, 25 June 2007 (UTC) In response to the link to an Erlang comparision at the wiki page Talk:SantaClausProblem , I am posting this roughly 34 lines of code adaptation of the Erlang message passing soultion:

-- by Chris Kuklewicz, looking at http://www.cs.otago.ac.nz/staffpriv/ok/santa/index.htm
-- This makes extensive use of sending partly or fully curried
-- commands through Chan and TChan.  Reindeer priority is implemented
-- using 'orElse'.  I did away with the extra secretary threads, since they
-- were not needed.  I used (replicateM count (readTChan chan))) instead.
-- Santa should really use a Control.Concurrent.QSemN
module Santa(main) where

import Control.Monad(replicateM,replicateM_)
import Control.Concurrent(newChan,readChan,writeChan,threadDelay,forkIO)
import Control.Concurrent.STM(newTChanIO,readTChan,writeTChan,orElse,atomically)
import System.Random(randomRIO)

data Species a = Reindeer [a] | Elves [a]
forever x = x >> forever x

santa getNext self = forever (getNext >>= handle) where
  handle (Reindeer group) = do putStr "Ho, ho, ho!  Let's deliver toys!\n"
                               act group
  handle (Elves group)    = do putStr "Ho, ho, ho!  Let's meet in the study!\n"
                               act group
  act group = do sequence_ [tellMember (writeChan self ()) | tellMember <- group]
                 replicateM_ (length group) (readChan self)

worker tellSecretary msg self = forever $ do
  threadDelay =<< randomRIO (0,1000*1000) -- 0 to 1 second
  tellSecretary (writeChan self)
  tellGateKeeperIamDone <- readChan self
  putStr msg
  tellGateKeeperIamDone
  
spawnWorker tellSecretary before i after =
  forkIO (newChan >>= worker tellSecretary (before ++ show i ++ after))

secretary count species = do
  chan <- newTChanIO
  return (writeTChan chan,fmap species (replicateM count (readTChan chan)))

main = do
  (toRobin,fromRobin) <- secretary 9 Reindeer
  (toEdna,fromEdna) <- secretary 3 Elves
  sequence [ spawnWorker (atomically . toRobin) "Reindeer " i " delivering toys.\n"
             | i <- [1..9] ]
  sequence [ spawnWorker (atomically . toEdna) "Elf " i " meeting in the study.\n"
             | i <- [1..10] ]
  newChan >>= santa (atomically (fromRobin `orElse` fromEdna)) -- main thread is santa's