-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathlecture11.fsx
More file actions
186 lines (135 loc) · 4.68 KB
/
Copy pathlecture11.fsx
File metadata and controls
186 lines (135 loc) · 4.68 KB
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
(*
Lecture Nov 18, 2015: Generating data for testing: FsCheck continued
Based on https://fscheck.github.io/FsCheck/
If tests fail to run in Visual studio/Windows (FsUnit dll related error messages) then check that
your Help -> About Visual Studio shows that you have installed update 4 to VS2013 and appropriate
.Net framework updates. It is encouraged to test it in VS2015.
In MonoDevelop it is possible to get FsCheck with NUnit to work
by changing the target .Net framework to version 4.5, otherwise installing FsCheck and FsCheck.NUnit from NuGet will
fail with incompatible framework error.
*)
#r @"..\packages\FsCheck.2.2.1\lib\net45\FsCheck.dll"
open FsCheck
// Generators
// gen syntax uses computation expressions. let! will in this generator
// computation expression take care of getting an instance
// of a value from the instance of a generator (look at the type
// returned by Gen.choose, and the type of idx).
let chooseFromList xs =
gen {
let! idx = Gen.choose(0, List.length xs - 1)
return (List.nth xs idx)
}
// apparently nth is deprecated. Use the index syntax instead.
List.nth [1..5] 4
[1..5].[4]
let primeIsOdd =
Prop.forAll (Arb.fromGen (chooseFromList [2; 3; 5; 7; 11; 13] ))
(fun p -> p % 2 = 1)
Check.Quick(primeIsOdd)
let booleanGen =
Gen.oneof [
gen {return true}
gen {return false}
]
// We can change the distribution. In the following example case 2/3 of the
// values generated should be true
let optimist =
Gen.frequency [
(2, gen {return true})
(1, gen {return false})
]
// How to measure that? Well, let us define a property
// e.g. x implies x, that should hold. Let's add
// appropriate classifiers to it.
let xImpliesX (x : bool) =
(not x || x)
|> Prop.classify (x=true) "True"
|> Prop.classify (x=false) "False"
// Now define a property which will try to invalidate the
// above property. There is no point in trying true and false
// multpiple times, but we are interested in measuring the
// distribution.
let forAllXImpliesX =
Prop.forAll (Arb.fromGen (optimist2))
(fun x -> xImpliesX x)
Check.Quick forAllXImpliesX
type Tree =
| Leaf of int
| Branch of Tree * Tree
// This generator may generate arbitrarily big trees.
// Thus generating values itself may take considerable
// resources.
let rec unsafeTreeGen () =
Gen.oneof [
Gen.map Leaf Arb.generate<int>
Gen.map2 (fun left right -> Branch (left, right))
(unsafeTreeGen ())
(unsafeTreeGen ())
]
// Thus, we should limit the size of the generated data
// structure.
let treeGen =
let rec sizedTreeGen size =
match size with
| 0 -> Gen.map Leaf Arb.generate<int>
| _ -> let subtreeGen = sizedTreeGen (size / 2)
Gen.oneof [
Gen.map Leaf Arb.generate<int>
Gen.map2 (fun left right -> Branch (left, right))
subtreeGen
subtreeGen
]
Gen.sized sizedTreeGen
let rec leaves tree =
match tree with
| Leaf lab -> [lab]
| Branch (left, right) -> leaves left @ leaves right
let leavesNotEmpty =
Prop.forAll (Arb.fromGen treeGen)
(fun tree -> List.length (leaves tree) > 0)
Check.Verbose(leavesNotEmpty)
type Generators =
static member Tree () = {
new Arbitrary<Tree> () with
override arbitrary.Generator = treeGen
override arbitrary.Shrinker tree = Seq.empty
}
Arb.register<Generators>
let leavesNotEmpty' tree = List.length (leaves tree) > 0
Check.Verbose leavesNotEmpty'
// An example how to generate strings given a list of characters:
let createStringFromChars (cs : char list) =
gen {
let! chars = Gen.arrayOf (Gen.elements cs)
return System.String.Concat(chars)
}
// just to demonstrate the generated strings with a property that always holds:
let testStringGen =
Prop.forAll (Arb.fromGen (createStringFromChars ['A'; 'T'; 'G'; 'P'] ))
(fun p -> true)
Check.Verbose testStringGen
// Lazy
let x = printf "called me!" ; 1 + 2
x
let x' = lazy (printf "called me!" ; 1 + 2)
x'.Force()
x'.Force()
// Memoisation of functions
let addSimple (a , b) =
printfn "adding %d + %d" a b
a + b
addSimple (2, 3)
open System.Collections.Generic
let add =
let cache = new Dictionary<_,_>()
(fun x ->
match cache.TryGetValue x with
| true, v -> v
| _ -> let v = addSimple x
cache.Add(x,v)
v)
add(2,3)
add(2,3)
add(2,3)
add(2,4)