Phillip Trelford's Array

POKE 36879,255

FP Day Cambridge 2011

FP Day saw talks from luminaries in the Functional Programming world, Simon Peyton-Jones and Don Syme give key notes, with hands-on tutorials and experience reports on F#, Clojure and Haskell sandwiched in the middle. Tomas Petricek and I provided the F# filling, and Zach Bray applied the F# source.

FPDayLogo453x132

Turning to the Functional Side With F#

F# is a multi-paradigm programming language with first-class support for Functional Programming, and ships with Visual Studio 2010. Using a mixture of presentation and practical exercises this session aims to help you:

  • learn how to use F#
  • think in a functional way
  • model problem domains using functional types

Tasks Download: http://tomasp.net/fpday.zip & Code Samples on Github

The morning tasks were based on a Point-of-sale (POS) application.

Domain Model:

namespace Checkout

// Common types

type Code = string
type Name = string
type Price = decimal
type Product = Product of Code * Name * Price
type Quantity = decimal

/// Tender types
type Tender =
  | Cash
  | Card of string
  | Voucher

/// Represents line item
type LineItem = 
  | SaleLineItem of int * Product * Quantity
  | TenderLineItem of Tender * Price
  | CancelLineItem of int

Product lookup:

[<AutoOpen>]
module Products = 
    let products = [
            Product("8717644012208","Lynx Africa",2.49M)
            Product("5010123730215","Listerine",2.49M)
            Product("5000347009242","Aquafresh",1.99M)
            Product("5045094763863","Ibuprofen", 1.99M)]
    let Lookup code = 
        products |> Seq.tryFind (function Product(code',_,_) -> code' = code)

Functions to be implemented in the task:

[<AutoOpen>]
module Lines =
    let saleTotal lines =
        lines |> List.sumBy (fun line ->
            match line with
            | SaleLineItem(id,Product(_,_,price),quantity) -> price*quantity
            | _ -> 0.0M
        )
    let tenderTotal lines =
        raise (new System.NotImplementedException())
    let cancelTotal lines =
        raise (new System.NotImplementedException())

Sale type:

type Sale () =
    let mutable items = []    
    member sale.AddItem (item:LineItem) = items <- item::items
    member sale.TotalAmount = saleTotal items - cancelTotal items
    member sale.OutstandingAmount = sale.TotalAmount - tenderTotal items
    member sale.ChangeDue = 
        if sale.OutstandingAmount < 0M 
        then -sale.OutstandingAmount
        else 0M

Failing tests:

open NUnit.Framework

[<TestFixture>]
module Tests = 
  open System.Diagnostics

  [<Test>]
  let ``Over tendering with cash should give change`` () =
    let sale = Sale()
    let product = Product("123", "3 Pay As you Go", 10.0M)
    sale.AddItem(SaleLineItem(1, product, 1.0M))
    sale.AddItem(TenderLineItem(Cash,20.00M))
    Assert.That(sale.ChangeDue = 10.0M)

  [<Test>]
  let ``Tendering full amount with card should leave no change`` () =
    let sale = Sale()
    let product = Product("123", "3 Pay As you Go", 10.0M)
    sale.AddItem(SaleLineItem(1, product, 1.0M))
    sale.AddItem(TenderLineItem(Card("1234123412341234"), 10.00M))
    Assert.That(sale.ChangeDue = 0.0M)

  [<Test>]
  let ``Cancelled items should not be charged`` () = 
    let sale = Sale()
    let product = Product("123", "3 Pay As you Go", 10.0M)
    sale.AddItem(SaleLineItem(1, product, 1.0M))
    sale.AddItem(CancelLineItem(1))
    Assert.That(sale.OutstandingAmount = 0.0M)

  do
    ``Over tendering with cash should give change`` ()
    ``Tendering full amount with card should leave no change`` ()
    ``Cancelled items should not be charged`` ()

If you'd like to learn more about F#, there are still places left at the Progressive F# Tutorials at Skills Matter in London on November 3-4th:

progfsharp_tutorials

Comments are closed