[Haskell-cafe] How to write elegant Haskell programms? (long posting)

Michael Roth mroth at nessie.de
Mon Jan 29 14:14:55 EST 2007


Hello list,

I'm new to Haskell and I'm trying to learn how to write elegant code
using Haskell.

I decided to convert the following small tool, written in ruby:

===========================================================
#! /usr/bin/env ruby

require 'pathname'

BASENAMES       = %w{ mail.log thttpd.log }
ARCHIVEDIR      = Pathname.new '/var/log/archive'
LOGDIR          = Pathname.new '/var/log'

class Pathname
  def glob glob_pattern
    Pathname.glob self.join(glob_pattern)
  end
  def timestamp
    stat.mtime.strftime '%Y%m%d'
  end
end

for basename in BASENAMES
  for oldname in LOGDIR.glob "#{basename}.*.gz"
    newname = ARCHIVEDIR.join "#{basename}.#{oldname.timestamp}.gz"
    puts "mv #{oldname} #{newname}"
    File.rename oldname, newname
  end
end
===========================================================


My solution in Haskell is:

===========================================================
import System.Directory   (getDirectoryContents, getModificationTime,
renameFile)
import System.Locale      (defaultTimeLocale)
import System.Time        (ClockTime, toUTCTime, formatCalendarTime)
import Text.Regex         (mkRegex, matchRegex)
import Maybe
import Control.Monad

logdir, archivedir :: String
logfiles :: [String]

logfiles    = [ "mail.log", "thttpd.log" ]
logdir      = "/var/log"
archivedir  = "/var/log/archive"

basename :: String -> String
basename filename = head . fromMaybe [""] $ matchRegex rx filename where
  rx = mkRegex "^(.+)(\\.[0-9]+\\.gz)$"

isLogfile :: String -> Bool
isLogfile filename = basename filename `elem` logfiles

timestamp :: ClockTime -> String
timestamp time =
  formatCalendarTime defaultTimeLocale "%Y%m%d" (toUTCTime time)

makeOldname :: String -> String
makeOldname fn = logdir ++ '/' : fn

makeNewname :: String -> String -> String
makeNewname bn ts = archivedir ++ '/' : bn ++ '.' : ts ++ ".gz"

move :: String -> String -> IO ()
move oldname newname = do
  putStrLn $ "mv " ++ oldname ++ ' ' : newname
  renameFile oldname newname

main :: IO ()
main = do
  files <- liftM (filter isLogfile) (getDirectoryContents logdir)
  let oldnames = map makeOldname files
  times <- mapM getModificationTime oldnames
  let newnames = zipWith makeNewname (map basename files) (map timestamp
times)
  zipWithM_ move oldnames newnames
===========================================================


Ok, the tool written in Haskell works. But, to me, the source doesn't
look very nice and even it is larger than the ruby solution, and more
imporant, the programm flow feels (at least to me) not very clear.

Are there any libraries available to make writing such tools easier?
How can I made the haskell source looking more beautiful?


Michael Roth


-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 155 bytes
Desc: OpenPGP digital signature
Url : http://www.haskell.org/pipermail/haskell-cafe/attachments/20070129/bb3f0a2a/signature.bin


More information about the Haskell-Cafe mailing list