Created
July 31, 2021 18:33
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{- | |
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