Charlie Harvey

The simplest cleaning rota that could possibly work. Haskell edition

Living in a shared house can sometimes be troublesome; people have different living habits that can conflict with our own. In my house we recently agreed to start a cleaning rota to make sure that we were all doing our bit. The administrative overhead of a rota can be a pain, so I implemented a very simple rota system in Haskell to run as a cron job.

colourful brooms

The approach I took was to set up a couple of lists, one of jobs and one of people. The I randomy shuffle the jobs list and cycle through the people assigning the jobs to them by zipping. The actual working code is pretty much a one liner.

I started by installing random-shuffle from Hackage which I will need to provide System.Random.Shuffle, which makes shuffling an Haskell list trivial. $ cabal install random-shuffle Resolving dependencies... Downloading MonadRandom-0.1.13... Configuring MonadRandom-0.1.13... Building MonadRandom-0.1.13... ... /home/charlie/.cabal/lib/x86_64-linux-ghc-7.6.3/random-shuffle-0.0.4 Registering random-shuffle-0.0.4... Installed random-shuffle-0.0.4

Next I set to work on rota.hs, by declaring some imports and setting up my lists of people and jobs. import Data.List import System.Random import System.Random.Shuffle ps = [ "Charlie: " , "Housemate1: " , "Housemate2: " ] js = [ "Hoover or sweep stairs" , "Clean cooker" , "Clean fridge" , "Hoover hall and landing" , "Clean and mop kitchen" , "Clean and hoover front room" , "Clean and mop upstairs bathroom" , "Clean and mop downstairs bathroom" , "Garden" , "Recycling, garden waste, bins and food waste" , "Trim hedge" ]

Now, I defined a rota function that randomly shuffles the js list, cycles the ps list, zips them together sorts the resulting list (to group by person) and returns it.rota = do g<-newStdGen h<-newStdGen return . sort $ zipWith (++) (cycle $ shuffle' ps (length ps) h) (shuffle' js (length js) g)

I also needed a main function, so I could run it as a cron job. All this does is print out a brief explanation, and monadically map over the person/job strings, printing them. main = do rs <- rota putStrLn "This is an automated cleaning rota reminder. Jobs are assigned randomly on the first of the month and a reminder sent out every week or so." putStrLn "I may have forgotten some important jobs, please tell me if so. Replies to this email ought to come through as expected\n" mapM_ putStrLn rs

Cron setup

Now I had that bit, I needed to have the script run each month and pipe the output to a file. This file could then be emailed to the housemates on a weekly basis — maybe we will drop the frequency if it turns out to be too annoying. So I added a monthly job to cron, with crontab -e 0 1 1 * * cd /home/charlie/rota && ./rota > cleaning-rotaAnd another job to send the email reminders0 15 1,8,15,23,28 * * cat /home/charlie/rota/cleaning-rota | mail -s "Reminder: Cleaning Rota"

Within less time than it took to write this blog, I was able to build the simplest thing that could possibly work. But of course it remains to be seen whether it actually does work…

Update: Graham pointed out that the original version of this code would mean that if the number of jobs were not divisible by the number of housemates, then the first housemate would get lumbered with the most jobs. So I have changed the code to randomly shuffle the list of housemates too. Thanks Graham!

Image from Shirley on pixabay


  • Be respectful. You may want to read the comment guidelines before posting.
  • You can use Markdown syntax to format your comments. You can only use level 5 and 6 headings.
  • You can add class="your language" to code blocks to help highlight.js highlight them correctly.

Privacy note: This form will forward your IP address, user agent and referrer to the Akismet, StopForumSpam and Botscout spam filtering services. I don’t log these details. Those services will. I do log everything you type into the form. Full privacy statement.