Skip to content

Instantly share code, notes, and snippets.

@tomwadeson
Created November 28, 2016 22:26
Show Gist options
  • Save tomwadeson/6cb231497bab091c1334b1ab2c0ff8f8 to your computer and use it in GitHub Desktop.
Save tomwadeson/6cb231497bab091c1334b1ab2c0ff8f8 to your computer and use it in GitHub Desktop.
module HarryPotter where
import qualified Data.Map.Strict as Map
import Data.Maybe (catMaybes)
type Copies = Int
type Discount = Double
type Price = Double
type DiscountScheme = Int -> Discount
data Sale = Sale Copies Discount
deriving (Eq, Show)
data Book = One | Two | Three | Four | Five
deriving (Eq, Ord, Show)
type Books = Map.Map Book Copies
-- TODO: Fix this shite
discount :: DiscountScheme
discount 2 = 0.05
discount 3 = 0.10
discount 4 = 0.20
discount 5 = 0.25
discount _ = 0.00
booksFromList :: [Book] -> Books
booksFromList = foldl' (\acc x -> Map.insertWith (+) x 1 acc) Map.empty
sales :: Books -> [Sale]
sales = catMaybes . sales' -- Sorry!
sales' :: Books -> [Maybe Sale]
sales' books
| Map.null books = []
| otherwise = let (books', sale) = bestValueSale books
in sale : sales' books'
bestValueSale :: Books -> (Books, Maybe Sale)
bestValueSale books
| Map.null books = (Map.empty, Nothing)
| otherwise = (books', Just sale)
where
numTitles = Map.size books
leastCopies = minimum . Map.elems $ books
sale = Sale (numTitles * leastCopies) (discount numTitles)
books' = Map.filter (>0) . Map.map (subtract leastCopies) $ books
totalPrice :: [Sale] -> Price
totalPrice = sum . map salePrice
salePrice :: Sale -> Price
salePrice (Sale copies discount) = 8.0 * fromIntegral copies * (1 - discount)
{-
*HarryPotter> totalPrice . sales . booksFromList $ [One, One, Two, Two, Three, Three, Four, Five]
51.6
-}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment