Skip to content

Instantly share code, notes, and snippets.

@sjoness
Created August 8, 2013 09:12
Show Gist options
  • Save sjoness/6183027 to your computer and use it in GitHub Desktop.
Save sjoness/6183027 to your computer and use it in GitHub Desktop.
module Main where
import System.IO
-- Extended exercise: supermarket billing
-- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-- Types of names, prices (pence) and bar-codes.
type Name = String
type Price = Int
type BarCode = Int
-- The database linking names prices and bar codes.
type Database = [ (BarCode,Name,Price) ]
-- The example database we use is
codeIndex :: Database
codeIndex = [ (4719, "Fish Fingers" , 121),
(5643, "Nappies" , 1010),
(3814, "Orange Jelly", 56),
(1111, "Hula Hoops", 21),
(1112, "Hula Hoops (Giant)", 133),
(1234, "Dry Sherry, 1lt", 540)]
-- The lists of bar codes, and of Name,Price pairs.
type TillType = [BarCode]
type BillType = [(Name,Price)]
-- The length of a line in the bill.
lineLength :: Int
lineLength = 30
formatPence :: Price -> String
formatPence p =
let
pounds = p `div` 100
pence = p `mod` 100
padding | pence < 10 = "0"
| otherwise = ""
in
show pounds ++ "." ++ padding ++ show pence
formatLine :: (Name,Price) -> String
formatLine (n,p) =
let
ln = length n
fp = formatPence p
lp = length fp
dots = replicate (lineLength - ln - lp) '.'
in
n ++ dots ++ fp ++ "\n"
formatLines :: BillType -> String
formatLines nps = concat [ formatLine np | np <- nps ]
makeTotal :: BillType -> Price
makeTotal nps = sum ps
where
(_,ps) = unzip nps
formatTotal :: Price -> String
formatTotal p = "\n" ++ formatLine ("Total",p)
formatBill :: BillType -> String
formatBill nps = formatLines nps ++
formatTotal (makeTotal nps)
look :: Database -> BarCode -> (Name,Price)
look db bc = head ([ (n,p) | (c,n,p) <- db, c==bc ] ++ [ui])
where
ui = ("Unknown Item", 0)
lookUp :: BarCode -> (Name, Price)
lookUp bc = look codeIndex bc
makeBill :: TillType -> BillType
makeBill tt = map lookUp tt
-----------------------------------------------------------
-- drs
-- added code for interactive program
-----------------------------------------------------------
readDB :: IO Database
readDB = do
contents <- readFile "db.txt"
let getProduct line = let [barcode,name,price] = words line
in (read barcode,read name,read price)
return [ getProduct line | line <- lines contents ]
scan :: IO Int
scan = do putStr "Scan > "
c <- getLine
return (read c)
scans :: IO [Int]
scans = do bc <- scan
if bc == 0
then return []
else do
bcs <- scans
return (bc:bcs)
main = do hSetBuffering stdout NoBuffering
bcs <- scans
putStr (formatBill (makeBill bcs))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment