Last active
December 29, 2015 14:49
-
-
Save devshorts/7686263 to your computer and use it in GitHub Desktop.
shopping cart question
This file contains 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
open System | |
type Percent = double | |
type Money = double | |
type Nth = int | |
type ProductType = | |
| Apple | |
| Orange | |
| Poo | |
type Coupon = | |
| NextItem of Percent | |
| AllItems of Percent | |
| Off of Nth * ProductType * Money | |
type Product = { Type: ProductType; Price: Money } | |
type Cart = | |
| Product of Product | |
| Coupon of Coupon | |
let cart = [ Coupon(Off (2, Apple, 0.5)); | |
Product({ Type = Orange; Price = 1.0 }); | |
Product({ Type = Poo; Price = 1.0 }); | |
Coupon(AllItems(0.5)); | |
Product({ Type = Apple; Price = 1.0 }); | |
Product({ Type = Apple; Price = 1.0 }); | |
Coupon(NextItem(0.5)); | |
Product({ Type = Apple; Price = 1.0 }); | |
Coupon(NextItem(0.90)); | |
Product({ Type = Poo; Price = 1.0 });] | |
let selectProducts cart = cart |> Seq.choose (function | Product(p) -> Some(p) | _ -> None) | |
let updateCartElement f = function | |
| Coupon(c) -> Coupon(c) | |
| Product(p) -> Product(f p) | |
let ``by%`` percent cartItem = | |
cartItem |> updateCartElement (fun product -> { product with Price = product.Price * (1.0 - percent) }) | |
let ``by$`` dollars cartItem = | |
cartItem |> updateCartElement (fun product -> { product with Price = product.Price - dollars}) | |
let sumCart cart = Seq.fold (fun acc i -> i.Price + acc) 0.0 cart | |
let nthBy predicate (nth:int) (arr:'a[]) offset = | |
if nth = 0 then None else | |
let mutable n = nth | |
let mutable count = offset | |
while n <> 0 && count < (Array.length arr) - 1 do | |
count <- count + 1 | |
if arr.[count] |> predicate then | |
n <- n - 1 | |
if n = 0 then Some(count) | |
else None | |
let isProduct = function | Product(_) -> true | _ -> false | |
let isProductType productType = function | Product(p) when p.Type = productType -> true | _ -> false | |
let update elem (arr:'a []) predicate = | |
arr.[elem] <- predicate arr.[elem] | |
arr | |
let applyToAllItems percent cart = cart |> Array.map (``by%`` percent) | |
let updateIndx predicate cart idx = | |
match idx with | |
| Some(value) -> cart |> update value <| predicate | |
| None -> cart | |
let discountNextBy percent cart (offset:int) = | |
let nextIndx = cart |> nthBy isProduct 1 <| offset | |
nextIndx |> updateIndx (``by%`` percent) cart | |
let discountNthType (nth, productType, dollars) cart (offset:int) = | |
let nthIndex = cart |> nthBy (isProductType productType) nth <| offset | |
nthIndex |> updateIndx (``by$`` dollars) cart | |
let byCartElement (cart:Cart []) idx = | |
match cart.[idx] with | |
| Coupon(c) -> | |
match c with | |
| AllItems percent -> cart |> applyToAllItems percent | |
| NextItem percent -> (cart, idx) ||> discountNextBy percent | |
| Off (nth, productType, dollars) -> (cart, idx) ||> discountNthType (nth, productType, dollars) | |
| _ -> cart | |
let modifyList predicate arr = | |
arr | |
|> Array.fold(fun (count, arr) _ -> (count + 1, predicate arr count)) (0, arr) | |
|> snd | |
let applyCoupons (cart: Cart[]) = cart |> Array.copy |> modifyList byCartElement | |
let price (cart: Cart[]) = cart |> applyCoupons |> selectProducts |> sumCart |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment