Sometimes, imperative programming is the right choice

April 14, 2008

I like functional programming, and I usually try to write my programs in any language with as few side effects as I can possibly manage without making the code impossible to read or completely unidiomatic. For many problems, I find functional solutions more elegant, and easier to come up with. But there are times when modifying a variable just seems like the cleanest and easiest thing to do.

I was writing a small Python script today, and I needed a function to give me the disk usage of a directory (yeah, I know the function is probably not as accurate as it should be, but for the task at hand, it’s Good Enough (TM).) I started out with nested generator expressions, but I quickly found out that an imperative version would be much more readable. Judge for yourself:

def dirsize(dirname):
    return sum(sum(os.path.getsize(os.path.join(t[0], filename))
               for filename in t[2]) + os.path.getsize(t[0])
               for t in os.walk(dirname))

def dirsize(dirname):
    size = 0
    for t in os.walk(dirname):
        size += os.path.getsize(t[0])
        for filename in t[2]:
            size += os.path.getsize(os.path.join(t[0], filename))
    return size

Haskell programs for the Beastie Boys fans

April 1, 2008

A few weeks ago, I wrote a Python script to entertain myself and a friend on IRC. We were fond of doing the YOU GOTTA FIGHT! FOR YOUR RIGHT! TO PAAAAAAAAAAAAARTY! lines from the Beastie Boys’ song, and eventually, we started replacing “party” by anything that began with “pa”. So I wrote the script to make sure we never ran out of weird things that you must fight for.

I decided to port the script to Haskell. Here it is. Please Haskellers, let me know if it could be improved.

module Main where

import Data.Char
import Data.List (isPrefixOf)
import System.IO
import System.Random

findWords :: String -> IO [String]
findWords filename = do
    content <- readFile filename
    let allLines = lines content
    return $ filter (\word -> "pa" `isPrefixOf` (map toLower word))
                    allLines

pickAction :: [String] -> IO String
pickAction words = do
    n <- randomRIO (0, length words - 1)
    m <- randomRIO (10, 20)
    let (c:cs) = words !! n
    return $ c : (replicate m 'a' ++ cs)

main :: IO ()
main = do
    words <- findWords "/usr/share/dict/words"
    action <- pickAction words
    putStrLn "YOU GOTTA FIGHT!"
    putStrLn "FOR YOUR RIGHT!"
    putStrLn $ "TO " ++ (map toUpper action) ++ "!"