I decided to revisit the Vending Machine code kata.
I flushed out the logic for this program via TDD.
I spent more time than I expected on the ‘return change’ feature of the vending machine.

Overall, it was a refreshing exercise that enabled me to think functionally again.

Here are the types that I flushed out via TDD:

```(*Types*)
type Coin =    Quarter | Dime | Nickel
type Product = Chips   | Soda | Gum

type Purchase = { Product:Product ; Balance:Coin list }

type SelectionResult =
| Purchased of Purchase
| Requires  of decimal
```

Here are the functions that I flushed out via TDD:

```(*Functions*)
let valueOf = function
| Quarter -> 0.25m
| Dime    -> 0.10m
| Nickel  -> 0.05m

let costOf = function
| Chips -> 0.25m
| Soda  -> 0.50m
| Gum   -> 0.10m

let balanceOf coins =

(0.0m , coins)
||> List.fold (fun balance coin -> balance + (valueOf coin))

let remaining balance product = (costOf product) - balance

let rec getChange balance change =

let rec get remaining change =

if remaining >= valueOf Quarter
then get (remaining - valueOf Quarter) (Quarter::change)

elif remaining >= valueOf Dime
then get (remaining - valueOf Dime) (Dime::change)

elif remaining >= valueOf Nickel
then get (remaining - valueOf Nickel) (Nickel::change)

else change

get balance []

let attemptPurchase product deposited =

if balanceOf deposited >= costOf product
then Purchased { Product=product
Balance= getChange (balanceOf deposited - costOf product) [] }
else Requires (product |> remaining (balanceOf deposited))

let select product balance =
balance |> attemptPurchase product
```

Here are the tests:

```[<Test>]
let ``depositing quarter results in \$.25 balance``() =

[Quarter] |> balanceOf
|> should equal 0.25

[<Test>]
let ``depositing dime results in \$.10 balance``() =

[Dime] |> balanceOf
|> should equal 0.10

[<Test>]
let ``depositing nickel results in \$.05 balance``() =

[Nickel] |> balanceOf
|> should equal 0.05

[<Test>]
let ``depositing quarter can purchase chips``() =

[Quarter]
|> select Chips
|> should equal ((Purchased {Product=Chips ; Balance=[] }))

[<Test>]
let ``depositing two quarters can purchase Soda``() =

[Quarter ; Quarter]
|> select Soda
|> should equal ((Purchased {Product=Soda ; Balance=[] }))

[<Test>]
let ``depositing 2 quarters equals balance of 50 cents`` () =
[Quarter ; Quarter]
|> balanceOf
|> should equal 0.50

[<Test>]
let ``depositing dime can purchase Gum``() =

[Dime]
|> select Gum
|> should equal ((Purchased {Product=Gum ; Balance=[] }))

[<Test>]
let ``depositing 1 quarter and attempting to buy soda requires 1 more .25 more`` () =
[Quarter]
|> select Soda
|> should equal (Requires 0.25m)

[<Test>]
let ``zero balance and attempting to buy soda requires .50 more`` () =
[]
|> select Soda
|> should equal (Requires 0.50m)

[<Test>]
let ``0.75 balance and attempting to buy soda requires returns 0.25`` () =
[Quarter ; Quarter ; Quarter]
|> select Soda
|> should equal (Purchased {Product=Soda ; Balance=[Quarter] })

[<Test>]
let ``0.85 balance and attempting to buy soda requires returns 0.35`` () =
[Quarter ; Quarter ; Quarter ; Dime]
|> select Soda
|> should equal (Purchased {Product=Soda ; Balance=[Dime ; Quarter] })
```

The entire source code is below:

```module VendingMachine

open NUnit.Framework
open Xunit
open FsUnit

(*Types*)
type Coin =    Quarter | Dime | Nickel
type Product = Chips   | Soda | Gum

type Purchase = { Product:Product ; Balance:Coin list }

type SelectionResult =
| Purchased of Purchase
| Requires  of decimal

(*Functions*)
let valueOf = function
| Quarter -> 0.25m
| Dime    -> 0.10m
| Nickel  -> 0.05m

let costOf = function
| Chips -> 0.25m
| Soda  -> 0.50m
| Gum   -> 0.10m

let balanceOf coins =

(0.0m , coins)
||> List.fold (fun balance coin -> balance + (valueOf coin))

let remaining balance product = (costOf product) - balance

let rec getChange balance change =

let rec get remaining change =

if remaining >= valueOf Quarter
then get (remaining - valueOf Quarter) (Quarter::change)

elif remaining >= valueOf Dime
then get (remaining - valueOf Dime) (Dime::change)

elif remaining >= valueOf Nickel
then get (remaining - valueOf Nickel) (Nickel::change)

else change

get balance []

let attemptPurchase product deposited =

if balanceOf deposited >= costOf product
then Purchased { Product=product
Balance= getChange (balanceOf deposited - costOf product) [] }
else Requires (product |> remaining (balanceOf deposited))

let select product balance =
balance |> attemptPurchase product

[<Test>]
let ``depositing quarter results in \$.25 balance``() =

[Quarter] |> balanceOf
|> should equal 0.25

[<Test>]
let ``depositing dime results in \$.10 balance``() =

[Dime] |> balanceOf
|> should equal 0.10

[<Test>]
let ``depositing nickel results in \$.05 balance``() =

[Nickel] |> balanceOf
|> should equal 0.05

[<Test>]
let ``depositing quarter can purchase chips``() =

[Quarter]
|> select Chips
|> should equal ((Purchased {Product=Chips ; Balance=[] }))

[<Test>]
let ``depositing two quarters can purchase Soda``() =

[Quarter ; Quarter]
|> select Soda
|> should equal ((Purchased {Product=Soda ; Balance=[] }))

[<Test>]
let ``depositing 2 quarters equals balance of 50 cents`` () =
[Quarter ; Quarter]
|> balanceOf
|> should equal 0.50

[<Test>]
let ``depositing dime can purchase Gum``() =

[Dime]
|> select Gum
|> should equal ((Purchased {Product=Gum ; Balance=[] }))

[<Test>]
let ``depositing 1 quarter and attempting to buy soda requires 1 more .25 more`` () =
[Quarter]
|> select Soda
|> should equal (Requires 0.25m)

[<Test>]
let ``zero balance and attempting to buy soda requires .50 more`` () =
[]
|> select Soda
|> should equal (Requires 0.50m)

[<Test>]
let ``0.75 balance and attempting to buy soda returns 0.25`` () =
[Quarter ; Quarter ; Quarter]
|> select Soda
|> should equal (Purchased {Product=Soda ; Balance=[Quarter] })

[<Test>]
let ``0.85 balance and attempting to buy soda returns 0.35`` () =
[Quarter ; Quarter ; Quarter ; Dime]
|> select Soda
|> should equal (Purchased {Product=Soda ; Balance=[Dime ; Quarter] })
```