Skip to content

Instantly share code, notes, and snippets.

@fpawel
Last active April 17, 2018 12:35
Show Gist options
  • Save fpawel/43740374ec8e038802817daa96a39978 to your computer and use it in GitHub Desktop.
Save fpawel/43740374ec8e038802817daa96a39978 to your computer and use it in GitHub Desktop.
А more ideological for F# 4.1 variant of https://fsharpforfunandprofit.com/posts/designing-for-correctness/
type CartItem = string
type EmptyState = NoItems
type PaidForState = { PaidItems : CartItem list;
Payment : decimal}
type ActiveState = { UnpaidItems : CartItem list; }
type Cart =
| Empty of EmptyState
| Active of ActiveState
| PaidFor of PaidForState
module State =
let addToEmpty item = [item]
let addToActive { UnpaidItems = state} itemToAdd =
Active { UnpaidItems = itemToAdd :: state }
let removeFromActive { UnpaidItems = state} itemToRemove =
match List.filter (fun i -> i<>itemToRemove) state with
| [] -> Empty NoItems
| newList -> Active { UnpaidItems = newList }
let payForActive { UnpaidItems = state} amount =
PaidFor {PaidItems=state; Payment=amount}
module Cart =
let empty = Empty NoItems
let add item = function
| Empty _ -> Active { UnpaidItems = State.addToEmpty item }
| PaidFor _ as cart ->
printfn "ERROR: The cart is paid for"
cart
| Active state -> State.addToActive state item
let remove item = function
| Empty _ as cart ->
printfn "ERROR: The cart is empty"
cart // return the cart
| Active state as cart ->
State.removeFromActive state item
| PaidFor state as cart ->
printfn "ERROR: The cart is paid for"
cart // return the cart
let display = function
| Empty _ ->
printfn "The cart is empty" // can't do state.Items
| Active state ->
printfn "The cart contains %A unpaid items" state
| PaidFor state ->
printfn "The cart contains %A paid items. Amount paid: %f"
state.PaidItems state.Payment
open Cart
let (~%%) = display
let pay = State.payForActive
printf "emptyCart="; %% empty
let cartA = add "A" empty
printf "cartA="; %% cartA
let cartAB = add "B" cartA
printf "cartAB="; %% cartAB
let cartB = remove "A" cartAB
printf "cartB="; %% cartB
let emptyCart2 = remove "B" cartB
printf "emptyCart2="; %% emptyCart2
let emptyCart3 = remove "B" emptyCart2 //error
printf "emptyCart3="; %% emptyCart3
// try to pay for cartA
let cartAPaid = match cartA with
| Empty _ | PaidFor _ -> cartA
| Active state -> pay state 100m
printf "cartAPaid="; %% cartAPaid
// try to pay for cartAB
let cartABPaid =
match cartAB with
| Empty _ | PaidFor _ -> cartAB // return the same cart
| Active state -> pay state 100m
// try to pay for cartAB again
let cartABPaidAgain =
match cartABPaid with
| Empty _ | PaidFor _ -> cartABPaid // return the same cart
| Active state -> pay state 100m
match cartABPaid with
| Empty state -> pay state 100m // compiler error
| PaidFor state -> pay state 100m // compiler error
| Active state -> pay state 100m // ok
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment