From HaskellWiki
Jump to navigation Jump to search

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
-- 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
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