-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathChapter5.fsx
229 lines (166 loc) · 5.43 KB
/
Chapter5.fsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
// 5.3: Modeling Simple Values
type CustomerId = CustomerId of int
type WidgetCode = WidgetCode of string // starting with "W" then 4 digits
type GizmoCode = GizmoCode of string // starting with "G" then 3 digits
type UnitQuantity = UnitQuantity of int
type KilogramQuantity = KilogramQuantity of decimal
let customerId = CustomerId 42
let (CustomerId innerValue) = customerId
printfn "%i" innerValue
let processCustomerId (CustomerId inner) = printfn "inner value is %i" inner
processCustomerId customerId
type UnitQuantity2 = int // type alias
[<Struct>]
type UnitQuantity3 = UnitQuantity3 of int
type UnitQuantities = UnitQuantities of int[]
// 5.4: Modeling Complex Data
type Undefined = exn
type CustomerInfo = Undefined // like the *hole* in Idris
type ShippingAddress = Undefined
type BillingAddress = Undefined
type OrderId = OrderId of int
type ProductId = ProductId of int
[<NoEquality;NoComparison>] // implemented in section 5.7
type OrderLine = {
OrderId: OrderId
ProductId : ProductId
Qty: int
}
with
member this.Key =
(this.OrderId, this.ProductId)
type BillingAmount = Undefined
type Order = {
CustomerInfo : CustomerInfo
ShippingAddress : ShippingAddress
BillingAddress : BillingAddress
OrderLines : OrderLine list
AmountToBill : BillingAmount
}
type ProductCode =
| Widget of WidgetCode
| Gizmo of GizmoCode
type OrderQuantity =
| Unit of UnitQuantity
| Kilogram of KilogramQuantity
// 5.5: Modeling Workflows with Functions
type UnvalidatedOrder = Undefined
type ValidatedOrder = Undefined
type ValidateOrder = UnvalidatedOrder -> ValidatedOrder
type AcknowledgementSent = Undefined
type OrderPlaced = Undefined
type BillableOrderPlaced = Undefined
type PlaceOrderEvents = {
AcknowledgementSent : AcknowledgementSent
OrderPlaced : OrderPlaced
BillableOrderPlaced : BillableOrderPlaced
}
type PlaceOrder = UnvalidatedOrder -> PlaceOrderEvents
type QuoteForm = Undefined
type OrderForm = Undefined
type EnvelopeContents = Undefined
type CategoriedMail = Undefined
type CategorizedMail =
| Quote of QuoteForm
| Order of OrderForm
type CategorizeInboundMail = EnvelopeContents -> CategoriedMail
type ProductCatalog = Undefined
type PricedOrder = Undefined
type CalculatePrices = OrderForm -> ProductCatalog -> PricedOrder
type CalculatePricesInput = {
OrderForm : OrderForm
ProductCatalog : ProductCatalog
}
type CalculatePrices2 = CalculatePricesInput -> PricedOrder
// 5.5.x: Documenting Effects in the Function Signature
type ValidateOrderWithEffect = UnvalidatedOrder -> Result<ValidatedOrder, ValidationError list>
and ValidationError = {
FieldName : string
ErrorDescription : string
}
type ValidationResponse<'a> = Async<Result<'a, ValidationError list>>
type ValidateOrderAsync = UnvalidatedOrder -> ValidationResponse<ValidatedOrder>
// 5.6: A Question of Identity: Value Objects
let widgetCode1 = WidgetCode "W1234"
let widgetCode2 = WidgetCode "W1234"
printfn "Codes are equal? %b" (widgetCode1 = widgetCode2)
type Person = {FirstName: string; LastName: string}
let name1 = {FirstName="Alex"; LastName="Adams"}
let name2 = {FirstName="Alex"; LastName="Adams"}
printfn "Names are equal? %b" (name1 = name2)
type Address = {StreetAddress: string; City: string; Zip: string}
let address1 = {StreetAddress="123"; City="bj"; Zip="100037"}
let address2 = {StreetAddress="123"; City="bj"; Zip="100037"}
printfn "Addresses are equal? %b" (address1 = address2) // structural equality
// 5.7: A Question of Identity: Entities
type PhoneNumber = PhoneNumber of string
type EmailAddress = EmailAddress of string
type ContactId = ContactId of int
type ContactRaw = {
ContactId: ContactId
PhoneNumber: PhoneNumber
EmailAddress: EmailAddress
}
// 5.7.x: Implementing Equality for Entities
// this OOP style implementation is not recommended
[<CustomEquality; NoComparison>]
type ContactOOP = {
ContactId: ContactId
PhoneNumber: PhoneNumber
EmailAddress: EmailAddress
}
with
override this.Equals(obj) =
match obj with
| :? ContactOOP as c -> this.ContactId = c.ContactId // what does ':?' mean?
| _ -> false
override this.GetHashCode() =
hash this.ContactId
let contactId = ContactId 1
let contact1 = {
ContactId = contactId
PhoneNumber = PhoneNumber "12345678"
EmailAddress = EmailAddress "[email protected]"
}
let contact2 = {
ContactId = contactId
PhoneNumber = PhoneNumber "56781234"
EmailAddress = EmailAddress "[email protected]"
}
printfn "ContactOOP are equal? %b" (contact1 = contact2)
// FP style implementation
[<NoEquality; NoComparison>]
type Contact = {
ContactId: ContactId
PhoneNumber: PhoneNumber
EmailAddress: EmailAddress
}
let contact3 = {
ContactId = contactId
PhoneNumber = PhoneNumber "12345678"
EmailAddress = EmailAddress "[email protected]"
}
let contact4 = {
ContactId = contactId
PhoneNumber = PhoneNumber "12345678"
EmailAddress = EmailAddress "[email protected]"
}
// printfn "%b" (contact3 = contact4)
// compile error:
// The type 'Contact' does not support the 'equality' constraint because it has the 'NoEquality' attribute
printfn "Contacts are equal? %b" (contact3.ContactId = contact4.ContactId)
// definition of OrderLine is above
let order1 = {
OrderId = OrderId 31
ProductId = ProductId 24
Qty = 123
}
let order2 = {
OrderId = OrderId 31
ProductId = ProductId 24
Qty = 987
}
printfn "Orders are equal? %b" (order1.Key = order2.Key)
let order3 = {order2 with Qty = 23}
printfn "Quantity of order3 is: %d" order3.Qty
// 5.8: Aggregates