F#: Computation Expressions (Bank Account Kata)

I have been avoiding the concept of Monads in my journey to learn F#. However, I know that sooner or later, I’m just going to have to man-up. As a result, I have been trying to qualify the need to leverage F#’s Computation Expression.

My current conclusion is that a Computation Expression within F# can enable a developer to implement cross-cutting concerns all within a unit of code that maintains functional plug & play within a functional domain model.

I implemented a sample Computation Expression below that handles security and logging:

(*Types*)
type UserName =  UserName  of string
type Password =  Password  of string
type FirstName = FirstName of string
type LastName =  LastName  of string
type Balance =   Balance   of decimal
 
type Credentials = { UserName:UserName;   Password:Password }
type Account =     { FirstName:FirstName; LastName:LastName; Balance:Balance }
 
type GetAuthenticationBuilder() =
    member this.Bind (credentials, f) = printf "Logged In: %A\n\n" credentials; f credentials
    member this.Return x   = x
 
(*Functions*) 
let getAuthentication = GetAuthenticationBuilder()
let authenticate credentials = 
    getAuthentication { 
        let! result = if credentials.UserName = UserName "Bizmonger"  &&
                         credentials.Password = Password "MyPassword"

                      then Some { FirstName=FirstName "Scott"
                                  LastName= LastName  "Nimrod"
                                  Balance=  Balance    99.99m }
                      else printf "Authentication failed: %A" credentials
                           None 
        return result }

Here’s the client that fails to authenticate:


(*Client*)
let result = { UserName= UserName "Bizmonger"
               Password= Password "LA LA LA Mutha #$%^!" } |> authenticate

Here’s the output below:

> 
Authentication failed: {UserName = UserName "Bizmonger";
 Password = Password "LA LA LA Mutha #$%^!";}Logged In: <null>


val result : Account option = None

> 

What’s interesting about the results above is that it appears that the Bind method of the GetAuthenticationBuilder gets invoked AFTER the primary expression’s execution.

Here’s a client that DOES authenticate:


(*Client*)
let result = { UserName= UserName "Bizmonger"
               Password= Password "MyPassword" } |> authenticate

Here’s the output:

> 
Logged In: Some {FirstName = FirstName "Scott";
      LastName = LastName "Nimrod";
      Balance = Balance 99.99M;}


val result : Account option = Some {FirstName = FirstName "Scott";
                                    LastName = LastName "Nimrod";
                                    Balance = Balance 99.99M;}

> 
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: