Last active
April 17, 2018 12:35
-
-
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/
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
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