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"
Tags: bonsai, carpenter, code, feet, Haskell, inches, kata, praxis, programming