Skip to content

Instantly share code, notes, and snippets.

@AbrahamAriel
Created July 31, 2021 18:33
Show Gist options
  • Save AbrahamAriel/f7dc64844b194c4c2714b0e9edb36ce9 to your computer and use it in GitHub Desktop.
Save AbrahamAriel/f7dc64844b194c4c2714b0e9edb36ce9 to your computer and use it in GitHub Desktop.
(2017) Haskell, Task 3. Supermarket Billing. This assignment was taken from the book, "Haskell: The Craft of Functional Programming Second Edition" by Simon Thompson. This is my poor attempt at functional programming. At least it worked out well albeit a rather ugly coding.
{-
Supermarket Billing.
Use produceBill to output the complete receipt.
eg. produceBill [1234, 4719, 3814, 1112, 1113, 1234, 0000, 666]
-}
-- Hide lookup from Prelude so we can use our own.
import Prelude hiding (lookup)
-- Types
type Name = String
type Price = Int
type Barcode = Int
type Database = [ (Barcode, Name, Price) ]
type TillType = [ Barcode ]
type BillType = [ (Name, Price) ]
-- Initialise database
codeIndex :: Database
codeIndex = [ (4719, "Fish Fingers", 121),
(5643, "Nappies", 1010),
(3814, "Orange Jelly", 56),
(1111, "Hula Hoops", 21),
(1112, "Hula Hoops (Giants)", 133),
(1234, "Dry Sherry, 1lt", 540) ]
-- Update database
addItem :: Database -> (Barcode, Name, Price) -> Database
addItem db (barcode, name, price) = [(barcode, name, price)] ++ db
removeItem :: Database -> (Barcode, Name, Price) -> Database
removeItem db (barcode, name, price) = [ item | item <- db, item /= (barcode, name, price) ]
updateDb :: Database -> (Barcode, Name, Price) -> Database
updateDb db (barcode, name, price) = (removeItem db (barcode, name, price)) >> (addItem db (barcode, name, price))
-- Maximum length of a string
lineLength :: Int
lineLength = 30
-- String formatting methods
formatPence :: Price -> String
formatPence price = (show (price `div` 100)) ++ "." ++ (show (price `mod` 100))
formatLine :: (Name, Price) -> String
formatLine (name, price) = name ++ (replicate (lineLength - length name - length (formatPence price)) '.') ++ (formatPence price) ++ "\n"
formatLines :: [(Name, Price)] -> String
formatLines xs = concat [formatLine(name, price) | (name, price) <- xs]
makeDiscount :: BillType -> Int
makeDiscount bill = count `div` 2 * 100
where count = (length [ (name) | (name, price) <- bill, name == "Dry Sherry, 1lt"])
formatDiscount :: Int -> String
formatDiscount n = "Discount" ++ (replicate (lineLength - 8 - (length (formatPence n))) '.') ++ (formatPence n)
makeTotal :: BillType -> Price
makeTotal bill = (sum [ price | (name, price) <- bill ]) - (makeDiscount bill)
formatTotal :: Price -> String
formatTotal total = "Total" ++ (replicate(lineLength - 5 - length (formatPence total)) '.') ++ (formatPence total)
formatBill :: BillType -> String
formatBill bill = (replicate 8 ' ') ++ "My Store" ++ (replicate 8 ' ') ++ "\n\n" ++ formatLines bill ++ "\n" ++ (formatDiscount (makeDiscount bill)) ++ "\n\n" ++ (formatTotal (makeTotal bill))
-- Item lookup methods
look :: Database -> Barcode -> (Name, Price)
look db bc
| len >= 1 = head item
| otherwise = ("Unknown Item", 0)
where
item = [ (name, price) | (barcode, name, price) <- db, bc == barcode ]
len = length item
lookup :: Barcode -> (Name, Price)
lookup bc = look codeIndex bc
-- List producing methods
makeBill :: TillType -> BillType
makeBill barcodes = [ lookup barcode | barcode <- barcodes, (lookup barcode) /= ("Unknown Item", 0) ]
-- Output final bill.
produceBill :: TillType -> IO ()
produceBill barcodes = putStrLn(formatBill (makeBill barcodes))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment