F#: Bank Account Kata

I wrote some F# code for handling bank account transactions.

I wrote the program by using a function driven approach instead of a type driven approach.

The main handlers are the following:

let handleWithdraw = function
                     | Withdraw   (account , amount) -> 
                            Some  (BeforeWithdrawal (account , -1m * amount),
                                   AfterWithdrawal  (debit account amount) )
                     | _ -> None

let handleDeposit =   function
                      | Deposit   (account , amount) -> 
                             Some (BeforeDeposit (account , 1m * amount),
                                   AfterDeposit  (credit account amount) )
                      | _ -> None

let handleTransfer =  function
                      | Transfer (fromAccount, toAccount, amount) ->
                        Some (Transferred ({ FromBalanceBefore=fromAccount
                                             ToBalanceBefore=  toAccount

                                             FromBalanceAfter= debit  fromAccount amount 
                                             ToBalanceAfter=   credit toAccount   amount } ,

                                           amount))
                      | _ -> None

The supporting functions that back the handlers are as follows:

let update account amount operator = account |>  function
           | Checking v -> Checking (v + (operator * amount))
           | Savings  v -> Savings  (v + (operator * amount))
           | Business v -> Business (v + (operator * amount))

let debit  account amount =  update account amount (- 1m)
let credit account amount =  update account amount (+ 1m)

Here are the types:

type Account =        
    | Checking of decimal
    | Savings  of decimal
    | Business of decimal

type Commands =
    | Withdraw of Account * decimal
    | Deposit  of Account * decimal
    | Transfer of Account * Account * decimal

type Response =
    | Withdrawal  of Account
    | Deposited   of Account
    | Transferred of TransferSummary * decimal

and Transaction =
    | BeforeDeposit of Account * decimal
    | AfterDeposit  of Account

    | BeforeWithdrawal of Account * decimal
    | AfterWithdrawal  of Account

and TransferSummary = { 
    FromBalanceBefore: Account ; ToBalanceBefore: Account
    FromBalanceAfter:  Account ; ToBalanceAfter:  Account }

The entire program is below:

module BankAccountImpl

type Account =        
    | Checking of decimal
    | Savings  of decimal
    | Business of decimal

type Commands =
    | Withdrawal of Account * decimal
    | Deposit   of Account * decimal
    | Transfer  of Account * Account * decimal

type Response =
    | Withdrawal  of Account
    | Deposited   of Account
    | Transferred of TransferSummary * decimal

and Transaction =
    | BeforeDeposit of Account * decimal
    | AfterDeposit  of Account

    | BeforeWithdrawal of Account * decimal
    | AfterWithdrawal  of Account

and TransferSummary = { 
    FromBalanceBefore: Account ; ToBalanceBefore: Account
    FromBalanceAfter:  Account ; ToBalanceAfter:  Account }

(*Functions*)
let update account amount operator = account |>  function
           | Checking v -> Checking (v + (operator * amount))
           | Savings  v -> Savings  (v + (operator * amount))
           | Business v -> Business (v + (operator * amount))

let debit  account amount =  update account amount (- 1m)
let credit account amount =  update account amount (+ 1m)

let handleWithdraw = function
                     | Withdraw  (account , amount) -> 
                            Some (BeforeWithdrawal (account , -1m * amount),
                                  AfterWithdrawal  (debit account amount) )
                     | _ -> None

let handleDeposit =   function
                      | Deposit   (account , amount) -> 
                             Some (BeforeDeposit (account , 1m * amount),
                                   AfterDeposit  (credit account amount) )
                      | _ -> None

let handleTransfer =  function
                      | Transfer (fromAccount, toAccount, amount) ->
                        Some (Transferred ({ FromBalanceBefore=fromAccount
                                             ToBalanceBefore=  toAccount

                                             FromBalanceAfter= debit  fromAccount amount 
                                             ToBalanceAfter=   credit toAccount   amount } ,

                                           amount))
                      | _ -> None

(*Client*)
let deposit =    handleDeposit   (Deposit  (Checking 100m , 10m))
let withdraw =   handleWithdraw  (Withdrawal (Savings 100m , 10m))
let transfer =   handleTransfer  (Transfer (Checking 100m , Savings 150m , 10m))
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: