1
module NUnit.Samples.Money
4
open System.Collections.Generic
8
abstract Add : IMoney -> IMoney
9
abstract AddMoney : Money -> IMoney
10
abstract Multiply : int -> IMoney
11
abstract Negate : unit -> IMoney
12
abstract Subtract : IMoney -> IMoney
14
and Money(amount: int, currency: string) as this =
16
member internal this.currency
18
member internal this.amount
21
override self.Equals(anObject) =
23
| :? Money as money -> this.IsZero && money.IsZero || currency = money.currency && amount = money.amount
25
override this.GetHashCode() = currency.GetHashCode() + amount
26
override this.ToString() = System.String.Format("[{0} {1}]", amount, currency)
29
member this.IsZero = amount = 0
30
member this.Add(m: IMoney) = m.AddMoney(this)
31
member this.AddMoney(m: Money) = this.AddMoney(m)
32
member this.Multiply(factor) = this.Multiply(factor) :> IMoney
33
member this.Negate() = this.Negate() :> IMoney
34
member this.Subtract(m: IMoney) = this.Subtract(m) : IMoney
36
member this.IsZero = (this :> IMoney).IsZero
37
member this.Add(m: IMoney) = m.AddMoney(this)
38
member this.AddMoney(m: Money) =
39
if m.currency = this.currency then new Money(m.amount + this.amount, this.currency) :> IMoney
40
else new MoneyBag( [this; m] ) :> IMoney
41
member this.Multiply(factor) = new Money( this.amount * factor, this.currency )
42
member this.Negate() = new Money( -this.amount, this.currency)
43
member this.Subtract(m: IMoney) = m.Negate().Add(this);
46
static member (+) (m1: Money, m2: Money) = m1.AddMoney(m2)
47
static member (*) (m1: Money, factor) = m1.Multiply(factor)
48
static member (*) (factor, m1: Money) = m1.Multiply(factor)
49
static member (~-) (m: Money) = m.Negate()
50
static member (-) (m1: Money, m2: Money) = m1.Subtract(m2)
52
and MoneyBag(contents0: Money list) =
53
// Although mutable, this should only be changed in the constructor
54
let mutable contents = []
56
let mutable map = Map.empty
58
if m.IsZero <> true then
59
match map.TryFind(m.currency) with
60
| None -> map <- map.Add(m.currency, m.amount)
62
map <- map.Add(m.currency, m.amount + old.Value)
64
contents <- new Money(pair.Value, pair.Key)::contents
69
override this.Equals(anObject) =
71
| :? MoneyBag as bag when this.IsZero -> bag.IsZero
72
| :? MoneyBag as bag -> bag.contentsEqual(contents)
74
override this.GetHashCode() =
75
contents.GetHashCode()
76
override this.ToString() =
80
member this.IsZero = contents.IsEmpty
81
member this.Multiply(factor) = this.Multiply(factor) :> IMoney
82
member this.Negate() = this.Negate() :> IMoney
83
member this.Subtract(m: IMoney) = this.Subtract(m)
84
member this.Add(m: IMoney) : IMoney = this.Add(m)
85
member this.AddMoney(m: Money) = this.AddMoney(m) :> IMoney
87
member this.IsZero = contents.IsEmpty
88
member this.Multiply(factor) =
89
if factor = 0 then new MoneyBag( [] )
90
else new MoneyBag( [ for m in contents -> m * factor ] )
91
member this.Negate() = new MoneyBag( [ for m in contents -> -m ] )
92
member this.Add(m: IMoney): IMoney =
94
| :? Money as money -> this.AddMoney(money).simplify()
95
| :? MoneyBag as bag -> this.AddMoneyBag(bag).simplify()
96
| _ -> failwith "Unexpected Type for IMoney"
97
member this.AddMoney(money: Money): MoneyBag =
98
new MoneyBag( [ for m in contents -> if m.currency = money.currency then new Money(m.amount + money.amount, m.currency) else m ] )
99
member this.AddMoneyBag(bag: MoneyBag): MoneyBag =
100
let mutable result = bag
102
result <- result.AddMoney m
104
member this.Subtract(money: IMoney): IMoney = this.Add( money.Negate() )
106
member private self.contains(aMoney: Money) =
107
List.tryFind (fun m -> m = aMoney) contents <> None
108
member private self.contentsEqual(c: Money list) =
109
if c.Length <> contents.Length then false
110
else List.forall (fun m -> self.contains m) c
111
member private self.simplify() =
112
match contents.Length with
113
| 1 -> contents.Head :> IMoney
114
| _ -> self :> IMoney
116
static member (*) (bag: MoneyBag, factor) = bag.Multiply(factor)
117
static member (*) (factor, bag: MoneyBag) = bag.Multiply(factor)
118
static member (~-) (bag: MoneyBag) = bag.Negate()
119
static member (+) (bag: MoneyBag, m: IMoney) = bag.Add(m)
120
static member (+) (m: Money, bag: MoneyBag) = bag.AddMoney(m)
121
static member (-) (bag: MoneyBag, m: IMoney) = bag.Subtract(m)
122
static member (-) (m: Money, bag: MoneyBag) = m.Subtract(bag)