home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 3 / PDCD_3.iso / utilities / utilsf / hugs / hs / calendar < prev    next >
Text File  |  1995-02-14  |  4KB  |  115 lines

  1. -- This is a modification of the calendar program described in section 4.5
  2. -- of Bird and Wadler's ``Introduction to functional programming'', with
  3. -- two ways of printing the calendar ... as in B+W, or like UNIX `cal':
  4.  
  5. -- Picture handling:
  6.  
  7. infixr 5 `above`, `beside`
  8.  
  9. type Picture   =  [[Char]]
  10.  
  11. height, width :: Picture -> Int
  12. height p       = length p
  13. width  p       = length (head p)
  14.  
  15. above, beside :: Picture -> Picture -> Picture
  16. above          = (++)
  17. beside         = zipWith (++)
  18.  
  19. stack, spread :: [Picture] -> Picture
  20. stack          = foldr1 above
  21. spread         = foldr1 beside
  22.  
  23. empty         :: (Int,Int) -> Picture
  24. empty (h,w)    = copy h (copy w ' ')
  25.  
  26. block, blockT :: Int -> [Picture] -> Picture
  27. block n        = stack . map spread . group n
  28. blockT n       = spread . map stack . group n
  29.  
  30. group         :: Int -> [a] -> [[a]]
  31. group n []     = []
  32. group n xs     = take n xs : group n (drop n xs)
  33.  
  34. lframe        :: (Int,Int) -> Picture -> Picture
  35. lframe (m,n) p = (p `beside` empty (h,n-w)) `above` empty (m-h,n)
  36.          where h = height p
  37.                        w = width p
  38.  
  39. -- Information about the months in a year:
  40.  
  41. monthLengths year = [31,feb,31,30,31,30,31,31,30,31,30,31]
  42.                     where feb | leap year = 29
  43.                               | otherwise = 28
  44.  
  45. leap year         = if year`mod`100 == 0 then year`mod`400 == 0
  46.                                          else year`mod`4   == 0
  47.  
  48. monthNames        = ["January","February","March","April",
  49.              "May","June","July","August",
  50.              "September","October","November","December"]
  51.  
  52. jan1st year       = (year + last`div`4 - last`div`100 + last`div`400) `mod` 7
  53.                     where last = year - 1
  54.  
  55. firstDays year    = take 12
  56.                          (map (`mod`7)
  57.                               (scanl (+) (jan1st year) (monthLengths year)))
  58.  
  59. -- Producing the information necessary for one month:
  60.  
  61. dates fd ml = map (date ml) [1-fd..42-fd]
  62.               where date ml d | d<1 || ml<d  = ["   "]
  63.                               | otherwise    = [rjustify 3 (show d)]
  64.  
  65. -- The original B+W calendar:
  66.  
  67. calendar :: Int -> String
  68. calendar  = unlines . block 3 . map picture . months
  69.             where picture (mn,yr,fd,ml)  = title mn yr `above` table fd ml
  70.                   title mn yr    = lframe (2,25) [mn ++ " " ++ show yr]
  71.                   table fd ml    = lframe (8,25)
  72.                                           (daynames `beside` entries fd ml)
  73.                   daynames       = ["Sun","Mon","Tue","Wed","Thu","Fri","Sat"]
  74.                   entries fd ml  = blockT 7 (dates fd ml)
  75.                   months year    = zip4 monthNames
  76.                                         (copy 12 year)
  77.                                         (firstDays year)
  78.                                         (monthLengths year)
  79.  
  80. -- In a format somewhat closer to UNIX cal:
  81.  
  82. cal year = unlines (banner year `above` body year)
  83.            where banner yr      = [cjustify 75 (show yr)] `above` empty (1,75)
  84.                  body           = block 3 . map (pad . pic) . months
  85.                  pic (mn,fd,ml) = title mn `above` table fd ml
  86.                  pad p          = (side`beside`p`beside`side)`above`end
  87.                  side           = empty (8,2)
  88.                  end            = empty (1,25)
  89.                  title mn       = [cjustify 21 mn]
  90.                  table fd ml    = daynames `above` entries fd ml
  91.                  daynames       = [" Su Mo Tu We Th Fr Sa"]
  92.                  entries fd ml  = block 7 (dates fd ml)
  93.                  months year    = zip3 monthNames
  94.                                        (firstDays year)
  95.                                        (monthLengths year)
  96.  
  97. -- For a standalone calendar program:
  98.  
  99. {-
  100. main = getArgs exit (\strs ->
  101.        case strs of [year] -> calFor year
  102.                     _      -> appendChan stdout "Usage: cal year\n" exit done)
  103. -}
  104.  
  105. calFor year | illFormed = appendChan stderr "Bad argument" exit done
  106.             | otherwise = appendChan stdout (cal yr) exit done
  107.               where illFormed = null ds || not (null rs)
  108.                     (ds,rs)   = span isDigit year
  109.                     yr        = atoi ds
  110.                     atoi s    = foldl (\a d -> 10*a+d) 0 (map toDigit s)
  111.                     toDigit d = ord d - ord '0'
  112.        
  113.  
  114. -- End of calendar program
  115.