Archive for July, 2011

End of an Era

July 1, 2011

Last tuesday I got my PhD. Unfortunately, that has some consequences for this blog. Since I’ll now be working at a real job, which I’m starting monday, I won’t be able to do any Programming Praxis exercises during working hours anymore like I have for the past couple years. I’ll try and do some in the evenings now and then, but since I have a lot of other stuff to do, the frequency will be significantly reduced.

I hope you guys have enjoyed this blog over the past few years and I hope I’ve gotten at least a few of you to try out Haskell. If you haven’t, what are you waiting for? Go download the Haskell Platform and get started! Looking for something to practise on? Go do some of the exercises from Programming Praxis. I’m looking forward to reading your solutions.

Regards,
Remco Niemeijer

Programming Praxis – Feet And Inches

July 1, 2011

In today’s Programming Praxis exercise, our goal is to convert a decimal length value to the fractions used by carpenters. Let’s get started, shall we?

Some imports:

import Data.Ratio
import Text.Printf

To get proper rounding we first multiply by 32 and then see how many feet, inches and fractions of an inch there are.

toCarpenter :: RealFrac a => a -> (Int, Int, Ratio Int)
toCarpenter l = (feet, div r 32, mod r 32 % 32) where
    (feet, r) = divMod (round $ l * 32) (32 * 12)

Formatting the text is a unfortunately a tad unwieldy due to the number of special cases.

feetAndInches :: RealFrac a => a -> String
feetAndInches l = case toCarpenter l of
    (0,0,0) -> "0 feet 0 inches"
    (f,i,t) -> showUnit "foot" "feet" (f % 1) ++
               (if f > 0 && (i%1 + t) > 0 then " " else "") ++
               showUnit "inch" "inches" (i % 1 + t)
    where
    showUnit _ _ 0 = ""
    showUnit s m n = printf "%s %s" (showVal n) $ if n <= 1 then s else m
    showVal v | d == 1    = show n
              | v < 1     = printf "%d/%d" n d
              | otherwise = printf "%d and %d/%d" (div n d) (mod n d) d
              where (n,d) = (numerator v, denominator v)

Some tests to see if everything is working properly:

main :: IO ()
main = do print $ feetAndInches 0       == "0 feet 0 inches"
          print $ feetAndInches 0.2785  == "9/32 inch"
          print $ feetAndInches 1.6895  == "1 and 11/16 inches"
          print $ feetAndInches 11.9999 == "1 foot"
          print $ feetAndInches 12.2785 == "1 foot 9/32 inch"
          print $ feetAndInches 71.9999 == "6 feet"
          print $ feetAndInches 72      == "6 feet"
          print $ feetAndInches 72.3492 == "6 feet 11/32 inch"
          print $ feetAndInches 72.9999 == "6 feet 1 inch"
          print $ feetAndInches 73      == "6 feet 1 inch"
          print $ feetAndInches 73.0135 == "6 feet 1 inch"
          print $ feetAndInches 73.0185 == "6 feet 1 and 1/32 inches"
          print $ feetAndInches 73.8218 == "6 feet 1 and 13/16 inches"