├── .gitignore
├── packages
├── FsUnit.1.2.1.0
│ ├── tools
│ │ └── install.ps1
│ ├── FsUnit.1.2.1.0.nupkg
│ ├── Lib
│ │ ├── Net20
│ │ │ └── FsUnit.NUnit.dll
│ │ └── Net40
│ │ │ └── FsUnit.NUnit.dll
│ └── FsUnit.1.2.1.0.nuspec
├── NUnit.2.6.2
│ ├── license.txt
│ ├── NUnit.2.6.2.nupkg
│ ├── lib
│ │ └── nunit.framework.dll
│ └── NUnit.2.6.2.nuspec
├── Unquote.2.2.2
│ ├── Unquote.2.2.2.nupkg
│ ├── lib
│ │ ├── sl4
│ │ │ ├── Unquote.dll
│ │ │ └── Unquote.xml
│ │ └── net40
│ │ │ ├── Unquote.dll
│ │ │ └── Unquote.xml
│ └── Unquote.2.2.2.nuspec
└── repositories.config
├── Chapter_04_ex_4.fs
├── Program.fs
├── Chapter_05_ex_5.fs
├── packages.config
├── Complex.fsi
├── Chapter_03_ex_7.fs
├── Chapter_04_ex_3.fs
├── Chapter_08_ex_2.fs
├── README.md
├── Chapter_04_ex_17.fs
├── Chapter_04_ex_6.fs
├── Chapter_04_ex_18.fs
├── Chapter_03_ex_5.fs
├── Chapter_04_ex_7.fs
├── Vector.fsi
├── Chapter_03_ex_3_Tests.fs
├── Chapter_04_ex_9.fs
├── Chapter_03_ex_4_Tests.fs
├── Chapter_09_ex_3.fs
├── Chapter_05_ex_2.fs
├── App.config
├── Chapter_07_ex_2.fs
├── Chapter_04_ex_5.fs
├── Chapter_08_ex_1.fs
├── Chapter_09_ex_4.fs
├── Chapter_04_ex_16.fs
├── Chapter_04_ex_12.fs
├── Chapter_05_ex_1.fs
├── Chapter_04_ex_8.fs
├── Chapter_03_ex_4.fs
├── Chapter_05_ex_3.fs
├── Chapter_04_ex_14.fs
├── Chapter_05_ex_4.fs
├── Chapter_04_ex_1.fs
├── Chapter_03_ex_3.fs
├── Chapter_04_ex_19.fs
├── Chapter_08_ex_3.fs
├── FunctionalProgrammingUsingFSharp.sln
├── Chapter_07_ex_1.fs
├── Chapter_04_ex_2.fs
├── Chapter_04_ex_15.fs
├── Chapter_04_ex_10.fs
├── Chapter_09_ex_5.fs
├── Chapter_01_Tests.fs
├── Chapter_04_ex_13.fs
├── Chapter_06_ex_5.fs
├── Chapter_03_ex_1_Tests.fs
├── Chapter_06_ex_2.fs
├── Chapter_03_ex_2_Tests.fs
├── Chapter_03_ex_1.fs
├── Chapter_04_ex_20.fs
├── Chapter_03_ex_2.fs
├── Chapter_06_ex_1.fs
├── Chapter_06_ex_8.fs
├── Chapter_06_ex_4.fs
├── Chapter_04_ex_11.fs
├── Chapter_01.fs
├── Chapter_02_Tests.fs
├── Chapter_02.fs
├── FunctionalProgrammingUsingFSharp.fsproj
└── Chapter_06_ex_3.fs
/.gitignore:
--------------------------------------------------------------------------------
1 | Debug
2 |
3 | /bin/AutoTest.Net
4 |
--------------------------------------------------------------------------------
/packages/FsUnit.1.2.1.0/tools/install.ps1:
--------------------------------------------------------------------------------
1 | param($rootPath, $toolsPath, $package, $project)
2 |
3 | Add-BindingRedirect $project.Name
--------------------------------------------------------------------------------
/packages/NUnit.2.6.2/license.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TorbenRahbekKoch/Functional-Programming-Using-FSharp/HEAD/packages/NUnit.2.6.2/license.txt
--------------------------------------------------------------------------------
/packages/NUnit.2.6.2/NUnit.2.6.2.nupkg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TorbenRahbekKoch/Functional-Programming-Using-FSharp/HEAD/packages/NUnit.2.6.2/NUnit.2.6.2.nupkg
--------------------------------------------------------------------------------
/packages/Unquote.2.2.2/Unquote.2.2.2.nupkg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TorbenRahbekKoch/Functional-Programming-Using-FSharp/HEAD/packages/Unquote.2.2.2/Unquote.2.2.2.nupkg
--------------------------------------------------------------------------------
/packages/Unquote.2.2.2/lib/sl4/Unquote.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TorbenRahbekKoch/Functional-Programming-Using-FSharp/HEAD/packages/Unquote.2.2.2/lib/sl4/Unquote.dll
--------------------------------------------------------------------------------
/Chapter_04_ex_4.fs:
--------------------------------------------------------------------------------
1 | module Chapter_04_ex_4
2 |
3 | // 4.4 - This I cannot figure out...
4 | let rec altsum = function
5 | | [] -> 0
6 | | x0::x1::xs -> x0-x1 + altsum xs
--------------------------------------------------------------------------------
/packages/FsUnit.1.2.1.0/FsUnit.1.2.1.0.nupkg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TorbenRahbekKoch/Functional-Programming-Using-FSharp/HEAD/packages/FsUnit.1.2.1.0/FsUnit.1.2.1.0.nupkg
--------------------------------------------------------------------------------
/packages/NUnit.2.6.2/lib/nunit.framework.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TorbenRahbekKoch/Functional-Programming-Using-FSharp/HEAD/packages/NUnit.2.6.2/lib/nunit.framework.dll
--------------------------------------------------------------------------------
/packages/Unquote.2.2.2/lib/net40/Unquote.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TorbenRahbekKoch/Functional-Programming-Using-FSharp/HEAD/packages/Unquote.2.2.2/lib/net40/Unquote.dll
--------------------------------------------------------------------------------
/packages/FsUnit.1.2.1.0/Lib/Net20/FsUnit.NUnit.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TorbenRahbekKoch/Functional-Programming-Using-FSharp/HEAD/packages/FsUnit.1.2.1.0/Lib/Net20/FsUnit.NUnit.dll
--------------------------------------------------------------------------------
/packages/FsUnit.1.2.1.0/Lib/Net40/FsUnit.NUnit.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TorbenRahbekKoch/Functional-Programming-Using-FSharp/HEAD/packages/FsUnit.1.2.1.0/Lib/Net40/FsUnit.NUnit.dll
--------------------------------------------------------------------------------
/packages/repositories.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/Program.fs:
--------------------------------------------------------------------------------
1 | module Main_Module
2 | // Learn more about F# at http://fsharp.net
3 | // See the 'F# Tutorial' project for more help.
4 |
5 | []
6 | let main argv =
7 | printfn "%A" argv
8 | 0 // return an integer exit code
9 |
--------------------------------------------------------------------------------
/Chapter_05_ex_5.fs:
--------------------------------------------------------------------------------
1 | module Chapter_05_ex_5
2 | #if INTERACTIVE
3 | #r "packages/Unquote.2.2.2/lib/net40/unquote.dll"
4 | #r "packages/NUnit.2.6.2/lib/nunit.framework.dll"
5 | #endif
6 | open System
7 | open NUnit.Framework
8 | open Swensen.Unquote
9 |
10 |
11 |
--------------------------------------------------------------------------------
/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Complex.fsi:
--------------------------------------------------------------------------------
1 | module Complex
2 | []
3 | type Complex =
4 | static member ( + ) : Complex * Complex -> Complex
5 | static member ( - ) : Complex * Complex -> Complex
6 | static member ( * ) : Complex * Complex -> Complex
7 | static member ( / ) : Complex * Complex -> Complex
8 |
9 |
--------------------------------------------------------------------------------
/Chapter_03_ex_7.fs:
--------------------------------------------------------------------------------
1 | module Chapter_03_ex_7
2 |
3 | let isShape x = true
4 |
5 | type Shape =
6 | | Circle of float
7 | | Square of float
8 | | Triangle of float*float*float
9 |
10 | let area x =
11 | match x with
12 | | _ when not (isShape x) -> failwith "not a legal shape"
13 | | Circle r -> System.Math.PI * r * r
14 | | Square a -> a*a
15 | | Triangle(a, b, c) -> 42.0
--------------------------------------------------------------------------------
/Chapter_04_ex_3.fs:
--------------------------------------------------------------------------------
1 | module Chapter_04_ex_3
2 | open NUnit.Framework
3 | open FsUnit
4 |
5 | // 4.3 - with list comprehension
6 | let evenN n =
7 | [for x in 2..2..(n*2) do yield x]
8 | // for x in start..step..end
9 |
10 |
11 | []
12 | type ``Chapter_04_ex_3_Tests``() =
13 | []
14 | member x.``4.3 list comprehension with List.rev``() =
15 | evenN 10 |> should equal [2;4;6;8;10;12;14;16;18;20]
16 |
--------------------------------------------------------------------------------
/Chapter_08_ex_2.fs:
--------------------------------------------------------------------------------
1 | module chapter_08_ex_2
2 |
3 | // This is accepted by F# because the type inference is soooo cool.
4 | // If you only execute the first or the two first lines it will not
5 | // work, but when the third line with f(1) is executed it can figure
6 | // out that x in the second line is of type int and therefore
7 | // a must be a list of int.
8 | let mutable a = []
9 | let f x = a <- (x::a)
10 | f(1) // 1 is of type int (per definition)
11 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Functional-Programming-Using-FSharp
2 | ===================================
3 |
4 | Working through the book Functional Programming Using F# by Michael R. Hansen and Hans Rischel (http://www.cambridge.org/us/academic/subjects/computer-science/programming-languages-and-applied-logic/functional-programming-using-f)
5 |
6 | All exercices will have tests (where applicable), I will try to comment it thoroughly to make notice of problem areas, pitfalls and in general how and why I arrived at a particular solution.
--------------------------------------------------------------------------------
/Chapter_04_ex_17.fs:
--------------------------------------------------------------------------------
1 | module Chapter_04_ex_17
2 | #if INTERACTIVE
3 | #r "packages/Unquote.2.2.2/lib/net40/unquote.dll"
4 | #r "packages/NUnit.2.6.2/lib/nunit.framework.dll"
5 | #endif
6 | open System
7 | open NUnit.Framework
8 | open Swensen.Unquote
9 |
10 | // 4.17
11 | // The type is ('a -> bool) -> 'a list -> 'a list
12 | let rec p q = function
13 | | [] -> []
14 | | x::xs -> let ys = p q xs
15 | if q x then x::ys else ys @[x]
16 |
17 | p (fun x -> x % 2 = 1) [1;2;3;4]
18 | |> ignore
19 | // p q [x0;x1;x2;xn-1] ???
20 |
--------------------------------------------------------------------------------
/Chapter_04_ex_6.fs:
--------------------------------------------------------------------------------
1 | module Chapter_04_ex_6
2 | open NUnit.Framework
3 | open FsUnit
4 |
5 | // 4.6 - using a filter
6 | let rmeven numbers =
7 | numbers |> List.filter(fun item -> item % 2 > 0)
8 |
9 | []
10 | type ``Chapter_04_ex_6_Tests``() =
11 | []
12 | member x.``4.6 simple filtering``() =
13 | rmeven [] |> should equal []
14 | rmeven [2] |> should equal []
15 | rmeven [1] |> should equal [1]
16 | rmeven [2;4] |> should equal []
17 | rmeven [1;2;3;4;5;6] |> should equal [1;3;5]
18 |
--------------------------------------------------------------------------------
/Chapter_04_ex_18.fs:
--------------------------------------------------------------------------------
1 | module Chapter_04_ex_18
2 | #if INTERACTIVE
3 | #r "packages/Unquote.2.2.2/lib/net40/unquote.dll"
4 | #r "packages/NUnit.2.6.2/lib/nunit.framework.dll"
5 | #endif
6 | open System
7 | open NUnit.Framework
8 | open Swensen.Unquote
9 |
10 | // 4.18
11 | // The type is: ('a -> 'a) -> 'a list -> 'a list
12 | // g implicit param result
13 | let rec f g = function
14 | | [] -> []
15 | | x::xs -> g x :: f (fun y -> g(g y)) xs
16 |
17 | // f g [x0;x1;x2;....;xn-1] = ???
18 | // [g x0; g(g x1); g(g(g x2))... ??
--------------------------------------------------------------------------------
/Chapter_03_ex_5.fs:
--------------------------------------------------------------------------------
1 | module Chapter_03_ex_5
2 |
3 | type Equation = float*float*float
4 |
5 | type Solution =
6 | | NoSolution
7 | | OneRoot of float
8 | | TwoRoots of float*float
9 |
10 | let solve (a, b, c)=
11 | let discriminant = b*b - 4.0*a*c
12 | if discriminant < 0.0 then
13 | NoSolution
14 | else
15 | let sqrtDiscriminant = sqrt(discriminant)
16 | let x1 = (-b + sqrtDiscriminant)/ 2.0 * a
17 | if a = 0.0 then
18 | OneRoot(x1)
19 | else
20 | let x2 = (-b - sqrtDiscriminant)/ 2.0 * a
21 | TwoRoots(x1, x2)
22 |
--------------------------------------------------------------------------------
/Chapter_04_ex_7.fs:
--------------------------------------------------------------------------------
1 | module Chapter_04_ex_7
2 | open NUnit.Framework
3 | open FsUnit
4 |
5 | // 4.7 - filter and length
6 | let multiplicity x xs =
7 | xs
8 | |> List.filter(fun item -> item = x)
9 | |> List.length
10 |
11 | []
12 | type ``Chapter_04_ex_7_Tests``() =
13 | []
14 | member x.``4.7 filter and length``() =
15 | multiplicity 1 [] |> should equal 0
16 | multiplicity 2 [2] |> should equal 1
17 | multiplicity 1 [1] |> should equal 1
18 | multiplicity 2 [2;4] |> should equal 1
19 | multiplicity 1 [1;2;1;4;5;6] |> should equal 2
20 |
--------------------------------------------------------------------------------
/Vector.fsi:
--------------------------------------------------------------------------------
1 | // Code from Hansen and Rischel: Functional Programming using F# 16/12 2012
2 | // Chapter 7: Modules
3 |
4 | // From Section 7.3 and 7.4: Signature file for vector mudule with type augmentation
5 |
6 | module Vector
7 | []
8 | type Vector =
9 | static member ( ~- ) : Vector -> Vector
10 | static member ( + ) : Vector * Vector -> Vector
11 | static member ( - ) : Vector * Vector -> Vector
12 | static member ( * ) : float * Vector -> Vector
13 | static member ( * ) : Vector * Vector -> float
14 | val make : float * float -> Vector
15 | val coord: Vector -> float * float
16 | val norm : Vector -> float
17 |
--------------------------------------------------------------------------------
/Chapter_03_ex_3_Tests.fs:
--------------------------------------------------------------------------------
1 | module Chapter_03_ex_3_Tests
2 | open System
3 | open NUnit.Framework
4 | open FsUnit
5 | open Chapter_03_ex_3
6 |
7 | []
8 | type ``Chapter_03_ex_3_Tests``() =
9 | []
10 | member x.``3.3 add``() =
11 | (1.0, 1.0) .+ (2.0, 2.0) |> should equal (3.0, 3.0)
12 |
13 | []
14 | member x.``3.3 mul``() =
15 | (1.0, 1.0) .* (2.0, 2.0) |> should equal (0.0, 4.0)
16 |
17 | []
18 | member x.``3.3 sub``() =
19 | (1.0, 1.0) .- (2.0, 2.0) |> should equal (-1.0, -1.0)
20 |
21 | []
22 | member x.``3.3 div``() =
23 | (1.0, 1.0) ./ (2.0, 2.0) |> should equal (0.5, 0.0)
24 |
25 |
--------------------------------------------------------------------------------
/Chapter_04_ex_9.fs:
--------------------------------------------------------------------------------
1 | module Chapter_04_ex_9
2 | open NUnit.Framework
3 | open FsUnit
4 |
5 | // 4.9 - naive recursive version
6 | let rec zip (list1, list2) =
7 | match list1, list2 with
8 | | ([],[]) -> []
9 | | (head1::[], head2::[]) -> [(head1, head2)]
10 | | (head1::tail1, head2::tail2) when tail1.Length = tail2.Length ->
11 | (head1, head2)::zip (tail1, tail2)
12 | | _ -> failwith "Different lengths"
13 |
14 | []
15 | type ``Chapter_04_ex_9_Tests``() =
16 | []
17 | member x.``4.9 recursive``() =
18 | (fun () -> zip ([1;3], [2]) |> ignore) |> should throw typeof
19 | zip ([1;3], [2;4]) |> should equal [(1,2);(3,4)]
20 |
--------------------------------------------------------------------------------
/Chapter_03_ex_4_Tests.fs:
--------------------------------------------------------------------------------
1 | module Chapter_03_ex_4_Tests
2 | open System
3 | open NUnit.Framework
4 | open FsUnit
5 | open Chapter_03_ex_4
6 |
7 | []
8 | type ``Chapter_03_ex_4_Tests``() =
9 | []
10 | member x.``3.4 mirrorX tuple``() =
11 | mirrorX (1, 2) |> should equal (-1, -2)
12 |
13 | []
14 | member x.``3.4 mirrorX record``() =
15 | mirrorXRec {a=1.0;b=2.0} |> should equal {a= -1.0; b= -2.0}
16 |
17 | []
18 | member x.``3.4 mirrorY tuple``() =
19 | mirrorY (1, 2) |> should equal (-1, 2)
20 |
21 | []
22 | member x.``3.4 mirrorY record``() =
23 | mirrorYRec {a=1.0;b=2.0} |> should equal {a= -1.0; b= 2.0}
24 |
--------------------------------------------------------------------------------
/Chapter_09_ex_3.fs:
--------------------------------------------------------------------------------
1 | module Chapter_09_ex_3
2 | #if INTERACTIVE
3 | #r "packages/Unquote.2.2.2/lib/net40/unquote.dll"
4 | #r "packages/NUnit.2.6.2/lib/nunit.framework.dll"
5 | #endif
6 | open System
7 | open System.Globalization
8 | open NUnit.Framework
9 | open Swensen.Unquote
10 |
11 | // 9.3
12 |
13 | let sum (m, n) =
14 | let mutable result = m
15 | for value in 1..n do
16 | result <- result + (m + value)
17 | result
18 |
19 |
20 | []
21 | type ``Chapter 09 exercise 3 Tests``() =
22 | []
23 | member x.``9.3 Iterative sum(m,n)``() =
24 | test <@ sum(2,2) = 9@>
25 | test <@ sum(3, 2) = 12 @>
26 |
--------------------------------------------------------------------------------
/Chapter_05_ex_2.fs:
--------------------------------------------------------------------------------
1 | module Chapter_05_ex_2
2 | #if INTERACTIVE
3 | #r "packages/Unquote.2.2.2/lib/net40/unquote.dll"
4 | #r "packages/NUnit.2.6.2/lib/nunit.framework.dll"
5 | #endif
6 | open System
7 | open NUnit.Framework
8 | open Swensen.Unquote
9 |
10 | // 5.2
11 | let foldedRevrev (listOfList: int list list) =
12 | let reverseInner list =
13 | List.foldBack (fun item reversedList -> reversedList @ [item]) list []
14 |
15 | List.foldBack (fun item reversedList -> reversedList @ [(reverseInner item)]) listOfList []
16 |
17 | []
18 | type ``Chapter 05 exercise 2 Tests``() =
19 | []
20 | member x.``5.2 foldedRevrev``() =
21 | test <@ (foldedRevrev [[1;2;3];[4;5;6]]) = [[6;5;4];[3;2;1]] @>
22 |
--------------------------------------------------------------------------------
/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/Chapter_07_ex_2.fs:
--------------------------------------------------------------------------------
1 | module Complex
2 |
3 | type Complex = {
4 | real: float;
5 | imag: float
6 | }
7 | with
8 | static member (+) (left, right) =
9 | { real = left.real + right.real; imag = left.real + right.imag }
10 |
11 | static member (-) (left, right) =
12 | { real = left.real - right.real; imag = left.real - right.imag }
13 |
14 | static member (*) (left, right) =
15 | { real = left.real * right.real - left.imag * right.imag; imag = left.real + right.imag }
16 |
17 | static member (/) (left, right) =
18 | let divisor = (right.real*right.real + right.imag*right.imag)
19 | {
20 | real = (left.real * right.real + left.imag * right.imag)/divisor;
21 | imag = (left.imag * right.real - left.real * right.imag)/divisor
22 | }
23 |
--------------------------------------------------------------------------------
/Chapter_04_ex_5.fs:
--------------------------------------------------------------------------------
1 | module Chapter_04_ex_5
2 | open NUnit.Framework
3 | open FsUnit
4 |
5 | // 4.5 - simple filtering
6 | // Note that the numbering is zero-based, so the first item in the list is
7 | // considered being in an even position.
8 | let rmodd numbers =
9 | numbers
10 | |> List.mapi(fun index item -> (index, item))
11 | |> List.filter(fun (index, item) -> index % 2 = 0)
12 | |> List.map(fun (index, item) -> item)
13 |
14 |
15 |
16 | []
17 | type ``Chapter_04_ex_5_Tests``() =
18 | []
19 | member x.``4.5 mapping and filtering``() =
20 | rmodd [] |> should equal []
21 | rmodd [2] |> should equal [2]
22 | rmodd [2;4] |> should equal [2]
23 | rmodd [2;4;6;8;10;12;14;16;18;20] |> should equal [2;6;10;14;18]
24 |
--------------------------------------------------------------------------------
/Chapter_08_ex_1.fs:
--------------------------------------------------------------------------------
1 | module chapter_08_ex1
2 | #if INTERACTIVE
3 | #r "packages/Unquote.2.2.2/lib/net40/unquote.dll"
4 | #r "packages/NUnit.2.6.2/lib/nunit.framework.dll"
5 | #endif
6 | open System
7 | open System.Globalization
8 | open NUnit.Framework
9 | open Swensen.Unquote
10 |
11 | let mutable x = 1
12 | let mutable y = (x,2)
13 | let z = y
14 | x <- 7
15 |
16 | // I would have expected y to be (7, 2) - that is I would have expected it to be pointing
17 | // to (x, 2). But the expression (x,2) uses the ContentsOf operator (page 176) on x, since it's
18 | // a right side expression.
19 | test <@ fst y = 1 @>
20 |
21 | // Environment Store
22 | // ~> x |-> loc1 loc1: 1
23 | // ~> y |-> loc2 loc2: (1, 2)
24 | // ~> z |-> loc2
25 | // ~> x |-> loc1 loc1: 7
26 |
--------------------------------------------------------------------------------
/Chapter_09_ex_4.fs:
--------------------------------------------------------------------------------
1 | module Chapter_09_ex_4
2 | #if INTERACTIVE
3 | #r "packages/Unquote.2.2.2/lib/net40/unquote.dll"
4 | #r "packages/NUnit.2.6.2/lib/nunit.framework.dll"
5 | #endif
6 | open System
7 | open System.Globalization
8 | open NUnit.Framework
9 | open Swensen.Unquote
10 |
11 | // 9.4
12 |
13 | let listLength list =
14 | let mutable length = 0
15 | for item in list do
16 | length <- length+1
17 | length
18 |
19 | []
20 | type ``Chapter 09 exercise 4 Tests``() =
21 | []
22 | member x.``9.4 Iterative list length``() =
23 | test <@ listLength [] = 0 @>
24 | test <@ listLength [1] = 1 @>
25 | test <@ listLength [1;2;3;4;5;6] = 6 @>
26 |
--------------------------------------------------------------------------------
/Chapter_04_ex_16.fs:
--------------------------------------------------------------------------------
1 | module Chapter_04_ex_16
2 | #if INTERACTIVE
3 | #r "packages/Unquote.2.2.2/lib/net40/unquote.dll"
4 | #r "packages/NUnit.2.6.2/lib/nunit.framework.dll"
5 | #endif
6 | open System
7 | open NUnit.Framework
8 | open Swensen.Unquote
9 |
10 | // 4.16 - 1.
11 | // The type is int*int list -> int list
12 | let rec f = function
13 | | (x, []) -> []
14 | | (x, y::ys) -> (x+y)::f(x-1, ys)
15 |
16 | // f(x, [y0; y1; y2; y3; ...; yn-1] = [x+y0; x-1+y1; x-2+y2; x-3+y3;...;x-(n-1)+yn-1]
17 |
18 | // 4.16 - 2.
19 | // The type is 'a*'a list -> 'a*'a list
20 | let rec g = function
21 | | [] -> []
22 | | (x, y)::s -> (x, y)::(y, x)::g s
23 |
24 |
25 | // 4.16 - 3.
26 | // The type is 'a list -> 'a list
27 | let rec h = function
28 | | [] -> []
29 | | x::xs -> x::(h xs)@[x]
30 |
--------------------------------------------------------------------------------
/Chapter_04_ex_12.fs:
--------------------------------------------------------------------------------
1 | module Chapter_04_ex_12
2 | #if INTERACTIVE
3 | #r "packages/Unquote.2.2.2/lib/net40/unquote.dll"
4 | #r "packages/NUnit.2.6.2/lib/nunit.framework.dll"
5 | #endif
6 | open System
7 | open NUnit.Framework
8 | open Swensen.Unquote
9 |
10 | // 4.12 sum
11 | let sum (predicate, list)=
12 | let rec sum' (predicate: int -> bool) (list: int list) (currentSum:int) =
13 | match list with
14 | | [] -> currentSum
15 | | x::xs -> sum' predicate xs currentSum + (if predicate x then x else 0)
16 | sum' predicate list 0
17 |
18 | []
19 | type ``Chapter_04_ex_12_Tests``() =
20 | []
21 | member x.``4.12 predicate sum``() =
22 | test <@ sum ((fun x -> x > 0), [-1;0;1]) = 1 @>
23 | test <@ sum ((fun x -> x < 0), [-1;0;1]) = -1 @>
24 |
--------------------------------------------------------------------------------
/Chapter_05_ex_1.fs:
--------------------------------------------------------------------------------
1 | module Chapter_05_ex_1
2 | #if INTERACTIVE
3 | #r "packages/Unquote.2.2.2/lib/net40/unquote.dll"
4 | #r "packages/NUnit.2.6.2/lib/nunit.framework.dll"
5 | #endif
6 | open System
7 | open NUnit.Framework
8 | open Swensen.Unquote
9 |
10 | // 5.1
11 | // List.filter: ('a -> bool) -> 'a list -> 'a list
12 | let foldedFilter predicate items =
13 | List.foldBack (fun item state ->
14 | match predicate item with
15 | | false -> state
16 | | true -> item::state
17 | )
18 | items
19 | []
20 |
21 | []
22 | type ``Chapter 05 exercise 1 Tests``() =
23 | []
24 | member x.``5.1 foldedFilter``() =
25 | test <@ (foldedFilter (fun x -> x > 0) [-2;-1;0;1;2]) = [1;2] @>
--------------------------------------------------------------------------------
/Chapter_04_ex_8.fs:
--------------------------------------------------------------------------------
1 | module Chapter_04_ex_8
2 | open NUnit.Framework
3 | open FsUnit
4 |
5 | // 4.8 recursive (not tail-recursive)
6 | let rec split items =
7 | match items with
8 | | [] -> ([],[])
9 | | [x0] -> ([x0],[])
10 | | [x0;x1] -> ([x0],[x1])
11 | | x0::x1::xs -> let (r1, r2) = split xs
12 | (x0::r1, x1::r2)
13 |
14 | []
15 | type ``Chapter_04_ex_8_Tests``() =
16 | []
17 | member x.``4.8 recursive``() =
18 | split [] |> should equal ([], [])
19 |
20 | // This one is hard to test, since the value ([2],[]) has type int list*'a list
21 | // split [2] |> should equal ([2],[])
22 | split [2;4] |> should equal ([2],[4])
23 |
24 | split [1;2;3;4;5] |> should equal ([1;3;5],[2;4])
25 | split [1;2;3;4;5;6] |> should equal ([1;3;5],[2;4;6])
26 |
--------------------------------------------------------------------------------
/Chapter_03_ex_4.fs:
--------------------------------------------------------------------------------
1 | module Chapter_03_ex_4
2 |
3 | // 3.4 1.
4 | // A record type for a straight line:
5 | type StraightLineRec = {
6 | a: float
7 | b: float
8 | }
9 |
10 | // we can also use a tuple
11 | type StraightLine = float*float
12 |
13 | // 3.4 2.
14 | let mirrorX line =
15 | let a, b = line
16 | (-a, -b)
17 |
18 | let mirrorXRec (line: StraightLineRec) =
19 | let a, b = line.a, line.b
20 | { a= -a; b= -b}
21 |
22 | let mirrorY line =
23 | let a, b = line
24 | (-a, b)
25 |
26 | let mirrorYRec (line: StraightLineRec) =
27 | let a, b = line.a, line.b
28 | { a= -a; b=b}
29 |
30 | // 3.4 3.
31 | let formatStraightLine line =
32 | let a, b = line
33 | sprintf "y = %fx + %f" a b
34 |
35 | let formatStraightLineRec (line: StraightLineRec) =
36 | let a, b = line.a, line.b
37 | sprintf "y = %fx + %f" a b
38 |
--------------------------------------------------------------------------------
/Chapter_05_ex_3.fs:
--------------------------------------------------------------------------------
1 | module Chapter_05_ex_3
2 | #if INTERACTIVE
3 | #r "packages/Unquote.2.2.2/lib/net40/unquote.dll"
4 | #r "packages/NUnit.2.6.2/lib/nunit.framework.dll"
5 | #endif
6 | open System
7 | open NUnit.Framework
8 | open Swensen.Unquote
9 |
10 | // 5.3 conditional sum using foldBack
11 | let sum predicate items =
12 | List.foldBack (fun item currentSum ->
13 | match predicate item with
14 | | false -> currentSum
15 | | true -> item + currentSum
16 | )
17 | items
18 | 0
19 |
20 | []
21 | type ``Chapter 05 exercise 3 Tests``() =
22 | []
23 | member x.``5.3 conditional sum using foldBack``() =
24 | test <@ (sum (fun x -> x > 0) [-1;0;1]) = 1 @>
25 | test <@ (sum (fun x -> x < 0) [-1;0;1]) = -1 @>
26 |
--------------------------------------------------------------------------------
/Chapter_04_ex_14.fs:
--------------------------------------------------------------------------------
1 | module Chapter_04_ex_14
2 | #if INTERACTIVE
3 | #r "packages/Unquote.2.2.2/lib/net40/unquote.dll"
4 | #r "packages/NUnit.2.6.2/lib/nunit.framework.dll"
5 | #endif
6 | open System
7 | open NUnit.Framework
8 | open Swensen.Unquote
9 |
10 | // 4.14 - Find smallest int
11 | let findSmallestElement list =
12 | let rec find (list: int list) (currentSmallest:int) =
13 | match list with
14 | | [] -> None
15 | | x::[] -> Some(currentSmallest)
16 | | x::xs -> let newCurrentSmallest = Math.Min(x, currentSmallest)
17 | find xs newCurrentSmallest
18 | find list Int32.MaxValue
19 |
20 | []
21 | type ``Chapter_04_ex_14_Tests``() =
22 | []
23 | member x.``4.14 find smallest element option``() =
24 | test <@ findSmallestElement [5;2;8;2;6;2] = Some(2) @>
25 | test <@ findSmallestElement [] = None @>
26 |
--------------------------------------------------------------------------------
/Chapter_05_ex_4.fs:
--------------------------------------------------------------------------------
1 | module Chapter_05_ex_4
2 | #if INTERACTIVE
3 | #r "packages/Unquote.2.2.2/lib/net40/unquote.dll"
4 | #r "packages/NUnit.2.6.2/lib/nunit.framework.dll"
5 | #endif
6 | open System
7 | open NUnit.Framework
8 | open Swensen.Unquote
9 |
10 | // 5.4 downto1
11 | let downto1 f n e =
12 | if n > 0 then
13 | let items = [1..n]
14 | List.foldBack f items e
15 | else
16 | e
17 |
18 | let fact n =
19 | downto1 (*) n 1
20 |
21 |
22 | []
23 | type ``Chapter 05 exercise 4 Tests``() =
24 | []
25 | member x.``5.4 downto1 using foldBack``() =
26 | test <@ downto1 (+) 3 0 = 6 @>
27 | test <@ downto1 (+) 3 5 = 11 @>
28 | test <@ downto1 (+) -3 5 = 5 @>
29 |
30 | []
31 | member x.``5.4 factorial using downto1``() =
32 | test <@ fact 0 = 1 @>
33 | test <@ fact 1 = 1 @>
34 | test <@ fact 5 = 120 @>
35 |
36 |
--------------------------------------------------------------------------------
/Chapter_04_ex_1.fs:
--------------------------------------------------------------------------------
1 | module Chapter_04_ex_1
2 | open NUnit.Framework
3 | open FsUnit
4 |
5 | // 4.1
6 | // Using list comprehension
7 | let upto_a n =
8 | [for i in 1..n do yield i]
9 |
10 | // Recursive - and if I am correct - its tail-recursive - this will
11 | // do a stackoverflow, though, for negative values.
12 | // I don't personally like the upto' naming, its hard to read, its
13 | // hard to pronounce - in C# it probably would have been named
14 | // upto_impl, which is just as bad
15 | let rec upto_b n =
16 | let rec upto' n l =
17 | match n with
18 | | 0 -> l
19 | | x -> upto' (x-1) (x::l)
20 | upto' n []
21 |
22 | []
23 | type ``Chapter_04_ex_1_Tests``() =
24 | []
25 | member x.``4.1 list comprehension``() =
26 | upto_a 10 |> should equal [1;2;3;4;5;6;7;8;9;10]
27 |
28 | []
29 | member x.``4.1 recursive``() =
30 | upto_b 10 |> should equal [1;2;3;4;5;6;7;8;9;10]
31 |
--------------------------------------------------------------------------------
/packages/FsUnit.1.2.1.0/FsUnit.1.2.1.0.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | FsUnit
5 | 1.2.1.0
6 | Ray Vernagus and Daniel Mohl
7 | Ray Vernagus and Daniel Mohl
8 | http://fsunit.codeplex.com/license
9 | http://fsunit.codeplex.com/
10 | false
11 | FsUnit is a set of extensions that add special testing syntax to NUnit.
12 | The goals of FsUnit are to make unit-testing feel more functional while leverage existing testing frameworks.
13 | en-US
14 | F# fsharp NUnit FsUnit
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/Chapter_03_ex_3.fs:
--------------------------------------------------------------------------------
1 | module Chapter_03_ex_3
2 |
3 | type Complex = float * float
4 |
5 | // 3.3 1. Add and Multiply complex numbers represented as tuples
6 | let addComplex (n1:Complex) (n2:Complex) =
7 | let a, b = n1
8 | let c, d = n2
9 | (a + c, b + d)
10 |
11 | let mulComplex (n1:Complex) (n2:Complex) =
12 | let a, b = n1
13 | let c, d = n2
14 | (a*c - b*d, b*c + a*d)
15 |
16 | let (.+) n1 n2 = addComplex n1 n2
17 | let (.*) n1 n2 = mulComplex n1 n2
18 |
19 | // 3.3 2. Subtraction and Division
20 | let subtractComplex (n1:Complex) (n2:Complex) =
21 | let a, b = n1
22 | let c, d = n2
23 | (a - c, b - d)
24 |
25 | let divComplex (n1:Complex) (n2:Complex) =
26 | let a, b = n1
27 | let c, d = n2
28 | let divisor = (c*c + d*d)
29 | ((a*c + b*d)/divisor, ((b*c - a*d)/divisor))
30 |
31 | let (.-) n1 n2 = subtractComplex n1 n2
32 | let (./) n1 n2 = divComplex n1 n2
33 |
34 | // 3.3 3.
35 | // I usually do this without being told ;)
--------------------------------------------------------------------------------
/Chapter_04_ex_19.fs:
--------------------------------------------------------------------------------
1 | module Chapter_04_ex_19
2 | #if INTERACTIVE
3 | #r "packages/Unquote.2.2.2/lib/net40/unquote.dll"
4 | #r "packages/NUnit.2.6.2/lib/nunit.framework.dll"
5 | #endif
6 | open System
7 | open NUnit.Framework
8 | open Swensen.Unquote
9 |
10 | // 4. 19
11 | let rec isMember x = function
12 | | y::ys -> x=y || (isMember x ys)
13 | | [] -> false
14 |
15 | let areNb m c1 c2 =
16 | isMember(c1, c2) m || isMember(c2, c1) m
17 |
18 | // Well, if isMember(c1, c2) does not find it, it has to traverse the map again
19 | // looking of (c2, c1)
20 |
21 | let areNeighbors map country1 country2 =
22 | match map with
23 | | (countryX, countryY)::countries ->
24 | (country1 = countryX && country2 = countryY) ||
25 | (country2 = countryX && country1 = countryY)
26 | | [] -> false
27 |
28 | // The fully generic isMember cannot do this, since it has no knowledge of the
29 | // data structure it is comparing - is doesn't know that (x,y) = (y,x)
30 |
31 |
--------------------------------------------------------------------------------
/Chapter_08_ex_3.fs:
--------------------------------------------------------------------------------
1 | module Chapter_08_ex_3
2 | #if INTERACTIVE
3 | #r "packages/Unquote.2.2.2/lib/net40/unquote.dll"
4 | #r "packages/NUnit.2.6.2/lib/nunit.framework.dll"
5 | #endif
6 | open System
7 | open System.Globalization
8 | open NUnit.Framework
9 | open Swensen.Unquote
10 |
11 | // Environment // Store
12 | type t1 = { mutable a : int }
13 | type t2 = { mutable b : int; c : t1 }
14 | let x = { a = 1 } // x |-> { a |-> loc1 } loc1 : { a |-> loc2 }, loc2: 1
15 | let y = { b = x.a; c = x} // y |-> { b |-> 1; c |-> loc1 } loc3 : { b |-> loc2 }
16 | x.a <- 3 // loc2 : 3
17 |
18 | test <@ x.a = 3 @>
19 | test <@ y.b = 1 @> // First I would have expected y.b to be 3 - continued below...
20 | test <@ y.c.a = 3 @>
21 |
22 | // but the assignment b = x.a; uses the implicit ContentsOf operator introduced on page 176.
--------------------------------------------------------------------------------
/FunctionalProgrammingUsingFSharp.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 2012
4 | Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FunctionalProgrammingUsingFSharp", "FunctionalProgrammingUsingFSharp.fsproj", "{53A0AE05-0A65-49AA-9606-4C7973AD96E4}"
5 | EndProject
6 | Global
7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
8 | Debug|Any CPU = Debug|Any CPU
9 | Release|Any CPU = Release|Any CPU
10 | EndGlobalSection
11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
12 | {53A0AE05-0A65-49AA-9606-4C7973AD96E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
13 | {53A0AE05-0A65-49AA-9606-4C7973AD96E4}.Debug|Any CPU.Build.0 = Debug|Any CPU
14 | {53A0AE05-0A65-49AA-9606-4C7973AD96E4}.Release|Any CPU.ActiveCfg = Release|Any CPU
15 | {53A0AE05-0A65-49AA-9606-4C7973AD96E4}.Release|Any CPU.Build.0 = Release|Any CPU
16 | EndGlobalSection
17 | GlobalSection(SolutionProperties) = preSolution
18 | HideSolutionNode = FALSE
19 | EndGlobalSection
20 | EndGlobal
21 |
--------------------------------------------------------------------------------
/Chapter_07_ex_1.fs:
--------------------------------------------------------------------------------
1 | module Vector
2 | #if INTERACTIVE
3 | #r "packages/Unquote.2.2.2/lib/net40/unquote.dll"
4 | #r "packages/NUnit.2.6.2/lib/nunit.framework.dll"
5 | #endif
6 | open System
7 | open System.Globalization
8 | open NUnit.Framework
9 | open Swensen.Unquote
10 |
11 | // 7.2
12 |
13 | type Vector = {
14 | x: float; y: float
15 | }
16 |
17 | let make (x, y) =
18 | {x = x; y = y}
19 |
20 | let coord vector =
21 | (vector.x, vector.y)
22 |
23 | let norm vector =
24 | sqrt(vector.x * vector.x + vector.y * vector.y)
25 |
26 | type Vector with
27 | static member (~-) vector =
28 | { x = -vector.x; y = -vector.y }
29 |
30 | static member (+) (left, right) =
31 | { x = left.x + right.x; y = left.y + right.y }
32 |
33 | static member (-) (left, right) =
34 | { x = left.x - right.x; y = left.y - right.y }
35 |
36 | static member (*) (constant: float, vector) =
37 | { x = constant * vector.x; y = constant * vector.y }
38 |
39 | static member (*) (left, right) =
40 | left.x * right.x + right.y * right.y
41 |
42 |
--------------------------------------------------------------------------------
/Chapter_04_ex_2.fs:
--------------------------------------------------------------------------------
1 | module Chapter_04_ex_2
2 | open NUnit.Framework
3 | open FsUnit
4 |
5 | // 4.2
6 | // Using list comprehension and rev
7 | let downto1a n =
8 | List.rev [for i in 1..n do yield i]
9 |
10 | // Using list comprehension without rev
11 | let downto1b n =
12 | [for i in 1..n do yield n-i+1]
13 |
14 | // Using tail-recursion (I hope)
15 | // Again, not too crazy about the ' naming. Eventually I will come up with
16 | // something I like better.
17 | let downto1c n =
18 | let rec downto1' n' l =
19 | match n' with
20 | | 0 -> l
21 | | x -> downto1' (x-1) ((n-x+1)::l)
22 | downto1' n []
23 |
24 |
25 | []
26 | type ``Chapter_04_ex_2_Tests``() =
27 | []
28 | member x.``4.2 list comprehension with List.rev``() =
29 | downto1a 10 |> should equal [10;9;8;7;6;5;4;3;2;1]
30 |
31 | []
32 | member x.``4.2 list comprehension without List.rev``() =
33 | downto1b 10 |> should equal [10;9;8;7;6;5;4;3;2;1]
34 |
35 | []
36 | member x.``4.2 tail recursion``() =
37 | downto1c 10 |> should equal [10;9;8;7;6;5;4;3;2;1]
38 |
39 |
--------------------------------------------------------------------------------
/Chapter_04_ex_15.fs:
--------------------------------------------------------------------------------
1 | module Chapter_04_ex_15
2 | #if INTERACTIVE
3 | #r "packages/Unquote.2.2.2/lib/net40/unquote.dll"
4 | #r "packages/NUnit.2.6.2/lib/nunit.framework.dll"
5 | #endif
6 | open System
7 | open NUnit.Framework
8 | open Swensen.Unquote
9 |
10 | // 4.15 revrev
11 | let revrev listOfList =
12 | let rec reverseInner list reversedList =
13 | match list with
14 | | [] -> reversedList
15 | | x::xs -> reverseInner xs (x::reversedList)
16 |
17 | let rec reverseList list reversedList =
18 | match list with
19 | | [] -> reversedList
20 | | x::xs -> reverseList xs ((reverseInner x [])::reversedList)
21 | reverseList listOfList []
22 |
23 | test <@ revrev [[1;2;3];[4;5;6]] = [[6;5;4];[3;2;1]] @>
24 | //
25 | //let rec reverseInner list reversedList =
26 | // match list with
27 | // | [] -> reversedList
28 | // | x::xs -> reverseInner xs (x::reversedList)
29 | //
30 | //test <@ revrev [1;2;3]] = [[6;5;4];[3;2;1;3]] @>
31 | //
32 | []
33 | type ``Chapter_04_ex_15_Tests``() =
34 | []
35 | member x.``4.15 revrev``() =
36 | test <@ revrev [[1;2;3];[4;5;6]] = [[6;5;4];[3;2;1]] @>
37 |
38 |
--------------------------------------------------------------------------------
/Chapter_04_ex_10.fs:
--------------------------------------------------------------------------------
1 | module Chapter_04_ex_10
2 | #if INTERACTIVE
3 | #r "packages/Unquote.2.2.2/lib/net40/unquote.dll"
4 | #r "packages/FsUnit.1.2.1.0/lib/net40/FsUnit.NUnit.dll"
5 | #r "packages/NUnit.2.6.2/lib/nunit.framework.dll"
6 | #endif
7 | open System
8 | open NUnit.Framework
9 | open FsUnit
10 | open Swensen.Unquote
11 |
12 | // TODO: Collapse some matches
13 | let rec prefix list1 list2 =
14 | match list1, list2 with
15 | | [],[] -> true
16 | | x1::[], [] -> false // list1 longer than list2 is per definition not a match
17 | | x1::[], x2::[] -> x1 = x2
18 | | x1::xs1, x2::[] -> false // list1 longer than list2 is per definition not a match// failwith "test"//x1 = x2 && prefix xs1 []
19 | | x1::[], x2::xs2 -> x1 = x2
20 | | x1::xs1, x2::xs2 -> x1 = x2 && prefix xs1 xs2
21 | | _ -> failwith "Incomplete match"
22 |
23 | []
24 | type ``Chapter_04_ex_10_Tests``() =
25 | []
26 | member x.``4.10 recursive``() =
27 | test <@ prefix [] [] = true @>
28 | test <@ prefix [1] [1] = true @>
29 | test <@ prefix [1;2] [1;2] = true @>
30 | test <@ prefix [1] [1;2] = true @>
31 | test <@ prefix [1] [1;2;3] = true @>
32 | test <@ prefix [1;2] [1;2;3] = true @>
33 | test <@ prefix [0] [1;2] = false @>
34 | test <@ prefix [1;2] [1] = false @>
35 |
36 |
37 |
--------------------------------------------------------------------------------
/packages/Unquote.2.2.2/Unquote.2.2.2.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Unquote
5 | 2.2.2
6 | Stephen Swensen
7 | Stephen Swensen
8 | http://www.apache.org/licenses/LICENSE-2.0
9 | http://code.google.com/p/unquote/
10 | https://unquote.googlecode.com/svn/trunk/logo.png
11 | false
12 | Unquote is not just another DSL or API for making unit test assertions. Instead, assertions are written as plain, statically-checked F# quoted expressions and test failure messages are given as step-by-step F# expression evaluations.
13 |
14 | Unquote integrates configuration-free with all exception-based unit testing frameworks including xUnit.net, NUnit, and MbUnit. Unquote may even be used within FSI sessions, enabling the direct migration of ad-hoc FSI tests during interactive development to formal test suites.
15 |
16 | In addition to its unit testing features, Unquote includes operators for evaluating, decompiling, and incrementally reducing quoted expressions.
17 | Write F# unit test assertions as quoted expressions, get step-by-step failure messages for free.
18 | F# fsharp unit-testing xunit nunit mbunit quotations tdd fsi
19 |
20 |
--------------------------------------------------------------------------------
/Chapter_09_ex_5.fs:
--------------------------------------------------------------------------------
1 | module Chapter_09_ex_5
2 | #if INTERACTIVE
3 | #r "packages/Unquote.2.2.2/lib/net40/unquote.dll"
4 | #r "packages/NUnit.2.6.2/lib/nunit.framework.dll"
5 | #endif
6 | open System
7 | open System.Globalization
8 | open NUnit.Framework
9 | open Swensen.Unquote
10 |
11 |
12 | // 9.5
13 | // The factorial function from page 206;
14 | let rec factA (n, m) =
15 | match (n, m) with
16 | | (0, m) -> m
17 | | (n, m) -> factA(n-1, n*m)
18 |
19 | let factC n =
20 | let rec factC' n c =
21 | if n = 1 then c 1
22 | else factC' (n-1) (fun res -> c(res * n))
23 | factC' n id
24 |
25 | // When passing a continuation you pass a function that 1: captures a value for the current
26 | // recursion level and 2: can compute the result given a value when the recursion has happened.
27 |
28 | // Runtime comparison
29 |
30 | let xs16 = List.init 1000000 (fun i -> 16)
31 | for i in xs16 do let _ = factA (i,1) in () // Real: 00:00:00.027, CPU: 00:00:00.027, GC gen0: 0, gen1: 0
32 |
33 | for i in xs16 do let _ = factC i in () // Real: 00:00:00.686, CPU: 00:00:00.755, GC gen0: 56, gen1: 0
34 |
35 | []
36 | type ``Chapter 09 exercise 5 Tests``() =
37 | []
38 | member x.``9.5 Factorial - continuation passing style``() =
39 | test <@ factC 2 = 2 @>
40 | test <@ factC 3 = 6 @>
41 | test <@ factC 4 = 24 @>
42 | test <@ factC 5 = 120 @>
43 |
44 |
--------------------------------------------------------------------------------
/packages/NUnit.2.6.2/NUnit.2.6.2.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | NUnit
5 | 2.6.2
6 | NUnit
7 | Charlie Poole
8 | Charlie Poole
9 | http://nunit.org/nuget/license.html
10 | http://nunit.org/
11 | http://nunit.org/nuget/nunit_32x32.png
12 | false
13 | NUnit features a fluent assert syntax, parameterized, generic and theory tests and is user-extensible. A number of runners, both from the NUnit project and by third parties, are able to execute NUnit tests.
14 |
15 | Version 2.6 is the seventh major release of this well-known and well-tested programming tool.
16 |
17 | This package includes only the framework assembly. You will need to install the NUnit.Runners package unless you are using a third-party runner.
18 | NUnit is a unit-testing framework for all .Net languages with a strong TDD focus.
19 | Version 2.6 is the seventh major release of NUnit.
20 |
21 | Unlike earlier versions, this package includes only the framework assembly. You will need to install the NUnit.Runners package unless you are using a third-party runner.
22 |
23 | The nunit.mocks assembly is now provided by the NUnit.Mocks package. The pnunit.framework assembly is provided by the pNUnit package.
24 | en-US
25 | test testing tdd framework fluent assert theory plugin addin
26 |
27 |
--------------------------------------------------------------------------------
/Chapter_01_Tests.fs:
--------------------------------------------------------------------------------
1 | module Chapter_01_Tests
2 | open NUnit.Framework
3 | open FsUnit
4 | open Chapter_01
5 |
6 | []
7 | type ``Chapter 01 Tests``() =
8 |
9 | []
10 | member x.``Exercise 1.1``() =
11 | g 7 |> should equal 11
12 |
13 | []
14 | member x.``Exercise 1.2``() =
15 | h1 1. 1. |> should (equalWithin 0.01) (System.Math.Sqrt(2.))
16 | h2 1. 1. |> should (equalWithin 0.01) (System.Math.Sqrt(2.))
17 |
18 | []
19 | member x.``Exercise 1.3 gf``() =
20 | gf 7 |> should equal 11
21 |
22 | []
23 | member x.``Exercise 1.3 gh``() =
24 | hf1 (1., 1.) |> should (equalWithin 0.01) (System.Math.Sqrt(2.))
25 | hf1 (2., 2.) |> should (equalWithin 0.01) (System.Math.Sqrt(8.))
26 | hf2 (1., 1.) |> should (equalWithin 0.01) (System.Math.Sqrt(2.))
27 | hf2 (2., 2.) |> should (equalWithin 0.01) (System.Math.Sqrt(8.))
28 |
29 | []
30 | member x.``Exercise 1.4``() =
31 | f14 1 |> should equal 1
32 | f14 2 |> should equal 3
33 | f14 3 |> should equal 6
34 | f14 4 |> should equal 10
35 |
36 | []
37 | member x.``Exercise 1.5``() =
38 | fib 0 |> should equal 0
39 | fib 1 |> should equal 1
40 | fib 2 |> should equal 1
41 | fib 3 |> should equal 2
42 | fib 4 |> should equal 3
43 | fib 5 |> should equal 5
44 | fib 6 |> should equal 8
45 | fib 7 |> should equal 13
46 |
47 | []
48 | member x.``Exercise 1.6``() =
49 | sum(2, 2) |> should equal 9
50 | sum(3, 2) |> should equal 12
51 |
52 | []
53 | member x.``Exercise 1.7 Factorial``() =
54 | fact 2 |> should equal 2
55 | fact 3 |> should equal 6
56 | fact 5 |> should equal 120
57 |
--------------------------------------------------------------------------------
/Chapter_04_ex_13.fs:
--------------------------------------------------------------------------------
1 | module Chapter_04_ex_13
2 | #if INTERACTIVE
3 | #r "packages/Unquote.2.2.2/lib/net40/unquote.dll"
4 | #r "packages/NUnit.2.6.2/lib/nunit.framework.dll"
5 | #endif
6 | open System
7 | open NUnit.Framework
8 | open Swensen.Unquote
9 |
10 | // 4.13 - 1. find smallest element
11 | let findSmallestElement list =
12 | let rec find (list: int list) (currentSmallest:int) =
13 | match list with
14 | | [] -> currentSmallest
15 | | x::xs -> let newCurrentSmallest = Math.Min(x, currentSmallest)
16 | find xs newCurrentSmallest
17 | find list Int32.MaxValue
18 |
19 | // 4.13 - 2. delete
20 | let delete (list, itemToDelete) =
21 | let rec deleteItem list itemToRemove resultList =
22 | match list with
23 | | [] -> resultList
24 | | x::[] when x = itemToRemove -> resultList
25 | | x::xs when x = itemToRemove -> resultList @ xs
26 | | x::xs -> resultList @ [x] @ deleteItem xs itemToRemove resultList
27 | deleteItem list itemToDelete []
28 |
29 | // 4.13 - 3. sort
30 | let sortToWeak list =
31 | let rec weakSort rest result =
32 | match rest with
33 | | [] -> result
34 | | x::xs -> let smallestElement = findSmallestElement rest
35 | weakSort (delete(rest, smallestElement)) (result @ [smallestElement])
36 | weakSort list []
37 |
38 |
39 | []
40 | type ``Chapter_04_ex_13_Tests``() =
41 | []
42 | member x.``4.13.1 find smallest element``() =
43 | test <@ findSmallestElement [5;2;8;2;6;2] = 2 @>
44 |
45 | []
46 | member x.``4.13.2 delete element``() =
47 | test <@ delete([1;4;3;2;6;7;8;2;2;4;8], 2) = [1;4;3;6;7;8;2;2;4;8] @>
48 |
49 | []
50 | member x.``4.13.3 weak sort``() =
51 | test <@ sortToWeak [2;5;8;9;1;2;3] = [1;2;2;3;5;8;9] @>
52 |
53 |
54 |
--------------------------------------------------------------------------------
/Chapter_06_ex_5.fs:
--------------------------------------------------------------------------------
1 | module Chapter_06_ex_5
2 | #if INTERACTIVE
3 | #r "packages/Unquote.2.2.2/lib/net40/unquote.dll"
4 | #r "packages/NUnit.2.6.2/lib/nunit.framework.dll"
5 | #endif
6 | open System
7 | open System.Globalization
8 | open NUnit.Framework
9 | open Swensen.Unquote
10 |
11 | // 6.5 AncestorTree
12 | type AncestorTree =
13 | | Unspecified
14 | | Info of AncestorTree * string * AncestorTree
15 |
16 | // Grandfather1 Grandmother1 GrandFather2 unknown/unspec
17 | // father mother
18 | // child
19 |
20 | let tree = Info(
21 | Info(
22 | Info(
23 | Unspecified,
24 | "Grandfather1",
25 | Unspecified),
26 | "Father",
27 | Info(
28 | Unspecified,
29 | "Grandmother1",
30 | Unspecified)
31 | ),
32 | "Child",
33 | Info(
34 | Info(
35 | Unspecified,
36 | "Grandfather2",
37 | Unspecified),
38 | "Mother",
39 | Unspecified)
40 | )
41 |
42 | let maleAncestors tree =
43 | let rec collectMaleAncestors tree isFatherTree collectedValues =
44 | match tree, isFatherTree with
45 | | Unspecified,_ -> collectedValues
46 | | Info(fathers,male,mothers), true -> male::(collectMaleAncestors fathers true collectedValues)
47 | @ (collectMaleAncestors mothers false collectedValues)
48 | | Info(fathers,_,mothers), false -> (collectMaleAncestors fathers true collectedValues)
49 | @ (collectMaleAncestors mothers false collectedValues)
50 |
51 | collectMaleAncestors tree false []
52 |
53 | test <@ maleAncestors tree = ["Father"; "Grandfather1"] @>
54 |
--------------------------------------------------------------------------------
/Chapter_03_ex_1_Tests.fs:
--------------------------------------------------------------------------------
1 | module Chapter_03_ex_1_Tests
2 | open System
3 | open NUnit.Framework
4 | open FsUnit
5 | open Chapter_03_ex_1
6 |
7 | []
8 | type ``Chapter_03_Tests``() =
9 |
10 | []
11 | member x.``3.1 triple - no custom compare``() =
12 | (10, 10, "AM") < (10, 11, "AM") |> should equal true
13 | (10, 10, "PM") < (10, 11, "AM") |> should equal true // counter-intuitive ;)
14 |
15 | (10, 10, "AM") < (10, 10, "PM") |> should equal true
16 | (10, 10, "PM") < (10, 11, "PM") |> should equal true
17 |
18 | (11, 59, "AM") < (1, 15, "PM") |> should equal false // counter-intuitive
19 | (11, 00, "AM") < (1, 15, "AM") |> should equal false
20 |
21 | (11, 59, "AM") < (11, 59, "AM") |> should equal false
22 |
23 | []
24 | member x.``3.1 triple - custom compare``() =
25 | (10, 10, "AM") &< (10, 11, "AM") |> should equal true
26 | (10, 10, "PM") &< (10, 11, "AM") |> should equal false
27 |
28 | (10, 10, "AM") &< (10, 10, "PM") |> should equal true
29 | (10, 10, "PM") &< (10, 11, "PM") |> should equal true
30 |
31 | (11, 59, "AM") &< (1, 15, "PM") |> should equal true
32 | (11, 00, "AM") &< (1, 15, "AM") |> should equal false
33 |
34 | (11, 59, "AM") &< (11, 59, "AM") |> should equal false
35 |
36 | []
37 | member x.``3.1 record``() =
38 | { AmPm = AM; Hour=10; Minute=10 } < { AmPm = AM; Hour=10; Minute=11 } |> should equal true
39 | { AmPm = PM; Hour=10; Minute=10 } < { AmPm = AM; Hour=10; Minute=11 } |> should equal false
40 |
41 | { AmPm = AM; Hour=10; Minute=10 } < { AmPm = PM; Hour=10; Minute=10 } |> should equal true
42 | { AmPm = PM; Hour=10; Minute=10 } < { AmPm = PM; Hour=10; Minute=11 } |> should equal true
43 |
44 | { AmPm = AM; Hour=11; Minute=59 } < { AmPm = PM; Hour=1; Minute=15 } |> should equal true
45 | { AmPm = AM; Hour=11; Minute=00 } < { AmPm = AM; Hour=1; Minute=15 } |> should equal false
46 |
47 | { AmPm = AM; Hour=11; Minute=59 } < { AmPm = AM; Hour=11; Minute=59 } |> should equal false
--------------------------------------------------------------------------------
/Chapter_06_ex_2.fs:
--------------------------------------------------------------------------------
1 | module Chapter_06_ex_2
2 | #if INTERACTIVE
3 | #r "packages/Unquote.2.2.2/lib/net40/unquote.dll"
4 | #r "packages/NUnit.2.6.2/lib/nunit.framework.dll"
5 | #endif
6 | open System
7 | open System.Globalization
8 | open NUnit.Framework
9 | open Swensen.Unquote
10 |
11 | // 6.2 post fix form
12 | type Fexpr = | Const of float
13 | | X // What is this doing??
14 | | Add of Fexpr * Fexpr
15 | | Sub of Fexpr * Fexpr
16 | | Mul of Fexpr * Fexpr
17 | | Div of Fexpr * Fexpr
18 | | Sin of Fexpr
19 | | Cos of Fexpr
20 | | Log of Fexpr
21 | | Exp of Fexpr
22 |
23 | let rec toPostFix expression =
24 | match expression with
25 | | Const(value) -> String.Format(CultureInfo.InvariantCulture, "{0:0.0######}", value)
26 | | Add(left, right) -> toPostFix(left) + " " + toPostFix(right) + " +"
27 | | Sub(left, right) -> toPostFix(left) + " " + toPostFix(right) + " -"
28 | | Mul(left, right) -> toPostFix(left) + " " + toPostFix(right) + " *"
29 | | Div(left, right) -> toPostFix(left) + " " + toPostFix(right) + " /"
30 | | Sin(expr) -> toPostFix(expr) + " sin"
31 | | Cos(expr) -> toPostFix(expr) + " cos"
32 | | Log(expr) -> toPostFix(expr) + " log"
33 | | Exp(expr) -> toPostFix(expr) + " exp"
34 | | expr -> toPostFix(expr)
35 |
36 | []
37 | type ``Chapter 06 exercise 2 Tests``() =
38 | []
39 | member x.``6.2 format expressions in postfix form``() =
40 | test <@ toPostFix(Add(Const(7.0), Const(14.0))) = "7.0 14.0 +" @>
41 | test <@ toPostFix(Mul(
42 | Add(Const(7.0), Const(14.0)),
43 | Sub(Const(6.0), Const(12.0))))
44 | = "7.0 14.0 + 6.0 12.0 - *"
45 | @>
46 | test <@ toPostFix(Sin(
47 | Mul(
48 | Add(Const(7.0), Const(14.0)),
49 | Sub(Const(6.0), Const(12.0)))))
50 | = "7.0 14.0 + 6.0 12.0 - * sin"
51 | @>
52 |
--------------------------------------------------------------------------------
/Chapter_03_ex_2_Tests.fs:
--------------------------------------------------------------------------------
1 | module Chapter_03_ex_2_Tests
2 | open System
3 | open NUnit.Framework
4 | open FsUnit
5 | open Chapter_03_ex_2
6 |
7 | []
8 | type ``Chapter_03_ex_2_Tests``() =
9 | []
10 | member x.``3.2 triple add``() =
11 | (1, 0, 0) &+ (1, 0, 0) |> should equal (2, 0, 0)
12 | (1, 1, 1) &+ (1, 1, 1) |> should equal (2, 2, 2)
13 | (1, 1, 11) &+ (1, 1, 1) |> should equal (2, 3, 0)
14 | (1, 19, 11) &+ (1, 1, 1) |> should equal (3, 1, 0)
15 |
16 | []
17 | member x.``3.2 triple sub``() =
18 | (1, 0, 0) &- (1, 0, 0) |> should equal (0, 0, 0)
19 | (1, 1, 1) &- (1, 1, 1) |> should equal (0, 0, 0)
20 | (1, 1, 11) &- (1, 1, 1) |> should equal (0, 0, 10)
21 | (1, 19, 11) &- (1, 1, 1) |> should equal (0, 18, 10)
22 |
23 | (3, 1, 3) &- (1, 5, 6) |> should equal (1, 15, 9)
24 |
25 | []
26 | member x.``3.2 record add``() =
27 | { pound=1; shilling=0; pence=0} |+ { pound=1; shilling=0; pence=0} |> should equal { pound=2; shilling=0; pence=0}
28 | { pound=1; shilling=1; pence=1} |+ { pound=1; shilling=1; pence=1} |> should equal { pound=2; shilling=2; pence=2}
29 | { pound=1; shilling=1; pence=11} |+ { pound=1; shilling=1; pence=1} |> should equal { pound=2; shilling=3; pence=0}
30 | { pound=1; shilling=19; pence=11} |+ { pound=1; shilling=1; pence=1} |> should equal { pound=3; shilling=1; pence=0}
31 |
32 | []
33 | member x.``3.2 record sub``() =
34 | { pound=1; shilling=0; pence=0} |- { pound=1; shilling=0; pence=0} |> should equal { pound=0; shilling=0; pence=0}
35 | { pound=1; shilling=1; pence=1} |- { pound=1; shilling=1; pence=1} |> should equal { pound=0; shilling=0; pence=0}
36 | { pound=1; shilling=1; pence=11} |- { pound=1; shilling=1; pence=1} |> should equal { pound=0; shilling=0; pence=10}
37 | { pound=1; shilling=19; pence=11} |- { pound=1; shilling=1; pence=1} |> should equal { pound=0; shilling=18; pence=10}
38 | { pound=3; shilling=1; pence=3} |- { pound=1; shilling=5; pence=6} |> should equal { pound=1; shilling=15; pence=9}
39 |
40 | // 3*12 + 1*20 + 3
--------------------------------------------------------------------------------
/Chapter_03_ex_1.fs:
--------------------------------------------------------------------------------
1 | module Chapter_03_ex_1
2 |
3 | // 3.1 time test
4 |
5 | // Define an enum and a record type to hold a time.
6 | type Meridiem = AM | PM
7 |
8 | type Time = {
9 | AmPm : Meridiem
10 | Hour : int;
11 | Minute : int;
12 | }
13 |
14 | // Due to the built-in value comparison of records with comparable members
15 | // the comparison of Time records doesn't need any specific implementation,
16 | // since we have ordered the members deliberately to reflect that AmPm is more
17 | // important than Hour, etc.
18 | // This would also have worked if we used a string ("AM"/"PM") for the Meridiem.
19 | // If the record had been defined as below, it would not work, due to incorrect
20 | // ordering of the members:
21 |
22 | type Time2 = {
23 | Minute2 : int
24 | Hour2 : int
25 | AmPm2 : Meridiem
26 | }
27 |
28 | // Try running this in Interactive (together with Time2 and Meridiem definition
29 | // above) - it results in the value true, which is obviously wrong:
30 | let result2 = { AmPm2 = AM; Hour2=11; Minute2=10 } < { AmPm2 = AM; Hour2=10; Minute2=11 }
31 |
32 | // The triple definition, on the other hand, does need a specific function to
33 | // compare, when it is defined as in the book with (hour, minute, meridiem)
34 | // - that we are using a string for meridiem does not matter since "AM" does
35 | // sort before "PM".
36 | let lessThan (time1: int*int*string) (time2: int*int*string) =
37 | let (hour1, minute1, amPm1) = time1
38 | let (hour2, minute2, amPm2) = time2
39 | if (amPm1 < amPm2) then
40 | true
41 | elif (amPm1 = amPm2 && hour1 < hour2) then
42 | true
43 | elif (amPm1 = amPm2 && hour1 = hour2 && minute1 < minute2) then
44 | true
45 | else
46 | false
47 |
48 | let (&<) time1 time2 = lessThan time1 time2
49 |
50 | // If we were instead using (meridiem, hour, minute) instead, it would work out
51 | // of the box:
52 | let result3a = ("AM", 11, 10) < ("PM", 11, 10) // true
53 | let result3b = ("AM", 11, 10) < ("AM", 11, 11) // true
54 | let result3c = ("AM", 11, 10) < ("AM", 11, 9) // false
55 |
56 | // We have now learned that F# uses the definition order of the
57 | // record/tuple-members to compare by. Very nice, tidy and logical! :)
58 |
59 |
--------------------------------------------------------------------------------
/Chapter_04_ex_20.fs:
--------------------------------------------------------------------------------
1 | module Chapter_04_ex_20
2 | #if INTERACTIVE
3 | #r "packages/Unquote.2.2.2/lib/net40/unquote.dll"
4 | #r "packages/NUnit.2.6.2/lib/nunit.framework.dll"
5 | #endif
6 | open System
7 | open NUnit.Framework
8 | open Swensen.Unquote
9 | open Chapter_04_ex_19
10 |
11 | // 4.20
12 | // I can't help wondering whether functional programmers in general are:
13 | // 1. lazy - I mean how hard is it to write e.g colorMap map - instead of colMap m ?? ;)
14 | // 2. a bit aloof and reveling in slightly unreadable code ?? ;)
15 | // I think the code gets vastly more readable by using good names:
16 | let colorMap map =
17 | let areNeighbors map country1 country2 =
18 | match map with
19 | | (countryX, countryY)::countries ->
20 | (country1 = countryX && country2 = countryY) ||
21 | (country2 = countryX && country1 = countryY)
22 | | [] -> false
23 |
24 | // I'm still not fond of the ' naming here, but haven't come up with
25 | // something better, yet...
26 | // What's wrong with the ' ? Its hard to pronounce (doesn't really flow)
27 | // and it doesn't add any information to what the value is.
28 | let rec canColorBeExtendedBy map color country =
29 | match color with
30 | | [] -> true
31 | | country'::color' ->
32 | not(areNeighbors map country' country) &&
33 | canColorBeExtendedBy map color' country
34 |
35 | let rec extendColoring map colorings country =
36 | match colorings with
37 | | [] -> [[country]]
38 | | coloring::colorings' ->
39 | if canColorBeExtendedBy map coloring country then
40 | (country::coloring)::colorings'
41 | else
42 | coloring::extendColoring map colorings' country
43 |
44 | let addElement x ys = if isMember x ys then ys else x::ys
45 |
46 | let rec countries = function
47 | | [] -> []
48 | | (country1, country2)::rest -> addElement country1 (addElement country2 (countries rest))
49 |
50 | let rec colorCountries map = function
51 | | [] -> []
52 | | country::rest -> extendColoring map (colorCountries map rest) country
53 |
54 | colorCountries map (countries map)
55 |
56 |
57 |
--------------------------------------------------------------------------------
/Chapter_03_ex_2.fs:
--------------------------------------------------------------------------------
1 | module Chapter_03_ex_2
2 |
3 | // 3.2 with triple
4 |
5 | let addOldBritishMoney money1 money2 =
6 | let (pound1, shilling1, pence1) = money1
7 | let (pound2, shilling2, pence2) = money2
8 | let (pence, carry) =
9 | let sum = pence1 + pence2
10 | (sum % 12, sum / 12)
11 | let (shilling, carry) =
12 | let sum = shilling1 + shilling2 + carry
13 | (sum % 20, sum / 20)
14 | let pound = pound1 + pound2 + carry
15 | (pound, shilling, pence)
16 |
17 | let subtractOldBritishMoney money1 money2 =
18 | let (pound1, shilling1, pence1) = money1
19 | let (pound2, shilling2, pence2) = money2
20 |
21 | // Not sure whether it's called "carry" when subtracting... ;)
22 | let (pence, carry) =
23 | let difference = pence1 - pence2
24 | let willBorrow = difference < 0
25 | if willBorrow then (difference + 12, 1) else (difference, 0)
26 |
27 | let (shilling, carry) =
28 | let difference = shilling1 - shilling2 - carry
29 | let willBorrow = difference < 0
30 | if willBorrow then (difference + 20, 1) else (difference, 0)
31 |
32 | let (pound, carry) =
33 | let difference = pound1 - pound2 - carry
34 | let willBorrow = difference < 0
35 | if willBorrow then (difference + 10, 1) else (difference, 0)
36 |
37 | if (carry > 0) then
38 | failwith "You're out of money!"
39 | (pound, shilling, pence)
40 |
41 |
42 | let (&+) money1 money2 = addOldBritishMoney money1 money2
43 | let (&-) money1 money2 = subtractOldBritishMoney money1 money2
44 |
45 | // 3.2 with record
46 |
47 | type OldBritishMoney = {
48 | pence : int
49 | shilling : int
50 | pound : int
51 | }
52 |
53 | // The body of the function is actually the same as the body for the triple
54 | // above, so we could have called that directly
55 | let addOldBritishMoneyRec money1 money2 =
56 | let (pound1, shilling1, pence1) = (money1.pound, money1.shilling, money1.pence)
57 | let (pound2, shilling2, pence2) = (money2.pound, money2.shilling, money2.pence)
58 | let (pence, carry) =
59 | let sum = pence1 + pence2
60 | (sum % 12, sum / 12)
61 | let (shilling, carry) =
62 | let sum = shilling1 + shilling2 + carry
63 | (sum % 20, sum / 20)
64 | let pound = pound1 + pound2 + carry
65 | {pence = pence; shilling = shilling; pound = pound}
66 |
67 | // The body of the function is actually the same as the body for the triple
68 | // above, so we could have called that directly
69 | let subtractOldBritishMoneyRec money1 money2 =
70 | let (pound1, shilling1, pence1) = (money1.pound, money1.shilling, money1.pence)
71 | let (pound2, shilling2, pence2) = (money2.pound, money2.shilling, money2.pence)
72 | let (pence, carry) =
73 | let difference = pence1 - pence2
74 | let willBorrow = difference < 0
75 | if willBorrow then (difference + 12, 1) else (difference, 0)
76 |
77 | let (shilling, carry) =
78 | let difference = shilling1 - shilling2 - carry
79 | let willBorrow = difference < 0
80 | if willBorrow then (difference + 20, 1) else (difference, 0)
81 |
82 | let (pound, carry) =
83 | let difference = pound1 - pound2 - carry
84 | let willBorrow = difference < 0
85 | if willBorrow then (difference + 10, 1) else (difference, 0)
86 |
87 | if (carry > 0) then
88 | failwith "You're out of money!"
89 | {pence = pence; shilling = shilling; pound = pound}
90 |
91 | let (|+) money1 money2 = addOldBritishMoneyRec money1 money2
92 | let (|-) money1 money2 = subtractOldBritishMoneyRec money1 money2
93 |
--------------------------------------------------------------------------------
/Chapter_06_ex_1.fs:
--------------------------------------------------------------------------------
1 | module Chapter_06_
2 | #if INTERACTIVE
3 | #r "packages/Unquote.2.2.2/lib/net40/unquote.dll"
4 | #r "packages/NUnit.2.6.2/lib/nunit.framework.dll"
5 | #endif
6 | open System
7 | open NUnit.Framework
8 | open Swensen.Unquote
9 |
10 | // 6.1 expression reduction
11 | type Fexpr = | Const of float
12 | | X
13 | | Add of Fexpr * Fexpr
14 | | Sub of Fexpr * Fexpr
15 | | Mul of Fexpr * Fexpr
16 | | Div of Fexpr * Fexpr
17 | | Sin of Fexpr
18 | | Cos of Fexpr
19 | | Log of Fexpr
20 | | Exp of Fexpr
21 |
22 | let rec reduce expression =
23 | match expression with
24 | | Add(Const(left), Const(right)) -> Const(left + right)
25 | | Add(leftOp, Const(0.0)) -> reduce(leftOp)
26 | | Add(Const(0.0), rightOp) -> reduce(rightOp)
27 | | Add(left, right) -> reduce(Add(reduce(left), reduce(right)))
28 |
29 | | Sub(Const(left), Const(right)) -> Const(left - right)
30 | | Sub(leftOp, Const(0.0)) -> reduce(leftOp)
31 | | Sub(left, right) -> reduce(Sub(reduce(left), reduce(right)))
32 | //| Sub(Const(0.0), rightOp) -> reduce(rightOp)
33 |
34 | | Mul(Const(left), Const(right)) -> Const(left * right)
35 | | Mul(leftOp, Const(0.0)) -> Const(0.0)
36 | | Mul(Const(0.0), rightOp) -> Const(0.0)
37 | | Mul(left, right) -> reduce(Mul(reduce(left), reduce(right)))
38 |
39 | | Div(Const(left), Const(right)) -> Const(left / right)
40 | //| Div(leftOp, Const(0.0)) -> Const(0.0)
41 | | Div(Const(0.0), rightOp) -> Const(0.0)
42 | | Div(left, right) -> reduce(Div(reduce(left), reduce(right)))
43 |
44 | | Sin(expr) -> Sin(reduce(expr))
45 | | Cos(expr) -> Cos(reduce(expr))
46 | | Log(expr) -> Log(reduce(expr))
47 | | Exp(expr) -> Exp(reduce(expr))
48 |
49 | | expression -> expression
50 |
51 | []
52 | type ``Chapter 06 exercise 1 Tests``() =
53 | []
54 | member x.``6.1 reducing trivial expressions``() =
55 | test <@ reduce(Add(Const(7.0), Const(14.0))) = Const(21.0)@>
56 | test <@ reduce(Add(Const(0.0), Const(14.0))) = Const(14.0)@>
57 | test <@ reduce(Add(Const(7.0), Const(0.0))) = Const(7.0)@>
58 |
59 | test <@ reduce(Sub(Const(7.0), Const(14.0))) = Const(-7.0)@>
60 |
61 | test <@ reduce(Mul(Const(7.0), Const(14.0))) = Const(98.0)@>
62 | test <@ reduce(Mul(Const(0.0), Const(14.0))) = Const(0.0)@>
63 | test <@ reduce(Mul(Const(7.0), Const(0.0))) = Const(0.0)@>
64 |
65 | test <@ reduce(Div(Const(7.0), Const(14.0))) = Const(0.5)@>
66 | test <@ reduce(Div(Const(0.0), Const(14.0))) = Const(0.0)@>
67 |
68 | test <@ reduce(Add(Mul(Const(7.0), Const(2.0)), Div(Const(10.0), Const(5.0)))) = Const(16.0) @>
69 | test <@ reduce(Sub(Mul(Const(7.0), Const(2.0)), Div(Const(10.0), Const(5.0)))) = Const(12.0) @>
70 | test <@ reduce(Mul(Mul(Const(7.0), Const(2.0)), Div(Const(10.0), Const(5.0)))) = Const(28.0) @>
71 | test <@ reduce(Div(Mul(Const(7.0), Const(2.0)), Div(Const(10.0), Const(5.0)))) = Const(7.0) @>
72 |
73 | test <@ reduce(Sin(Mul(Const(7.0), Const(2.0)))) = Sin(Const(14.0))@>
74 | test <@ reduce(Cos(Mul(Const(7.0), Const(2.0)))) = Cos(Const(14.0))@>
75 | test <@ reduce(Log(Mul(Const(7.0), Const(2.0)))) = Log(Const(14.0))@>
76 | test <@ reduce(Exp(Mul(Const(7.0), Const(2.0)))) = Exp(Const(14.0))@>
77 |
--------------------------------------------------------------------------------
/Chapter_06_ex_8.fs:
--------------------------------------------------------------------------------
1 | module Chapter_06_ex_8
2 | #if INTERACTIVE
3 | #r "packages/Unquote.2.2.2/lib/net40/unquote.dll"
4 | #r "packages/NUnit.2.6.2/lib/nunit.framework.dll"
5 | #endif
6 | open System
7 | open System.Globalization
8 | open NUnit.Framework
9 | open Swensen.Unquote
10 |
11 | // 6.8 1. Stack and Interpret Instruction
12 | type Instruction =
13 | | ADD | SUB | MUL | DIV | SIN | COS | LOG | EXP | PUSH of float
14 |
15 | type Stack = float list
16 |
17 | let interpretInstruction stack instruction =
18 | match instruction, stack with
19 | | ADD, right::left::rest -> (left + right)::rest
20 | | SUB, right::left::rest -> (left - right)::rest
21 | | MUL, right::left::rest -> (left * right)::rest
22 | | DIV, right::left::rest -> (left / right)::rest
23 | | SIN, operand::rest -> (sin operand)::rest
24 | | COS, operand::rest -> (cos operand)::rest
25 | | LOG, operand::rest -> (log operand)::rest
26 | | EXP, operand::rest -> (exp operand)::rest
27 | | PUSH(value), stack -> value::stack
28 | | _ -> failwith "Illegal stack state for operation"
29 |
30 |
31 | // 6.8 2. interpretProgram
32 | let interpretProgram instructions =
33 | let rec executeProgram (stack: float list) instructions =
34 | match instructions with
35 | | [] -> stack.Head
36 | | instruction::rest -> let resultStack = interpretInstruction stack instruction
37 | executeProgram resultStack rest
38 | executeProgram [] instructions
39 |
40 | // 6.8 3. transform expression tree
41 |
42 | type Fexpr = | Const of float
43 | | X // What is this doing??
44 | | Add of Fexpr * Fexpr
45 | | Sub of Fexpr * Fexpr
46 | | Mul of Fexpr * Fexpr
47 | | Div of Fexpr * Fexpr
48 | | Sin of Fexpr
49 | | Cos of Fexpr
50 | | Log of Fexpr
51 | | Exp of Fexpr
52 |
53 | let rec transformFexpr expression x =
54 | match expression with
55 | | Const(value) -> [PUSH(value)]
56 | | Add(left, right) -> (transformFexpr left x) @ (transformFexpr right x) @ [ADD]
57 | | Sub(left, right) -> (transformFexpr left x) @ (transformFexpr right x) @ [SUB]
58 | | Mul(left, right) -> (transformFexpr left x) @ (transformFexpr right x) @ [MUL]
59 | | Div(left, right) -> (transformFexpr left x) @ (transformFexpr right x) @ [DIV]
60 | | Sin(expr) -> (transformFexpr expr x) @ [SIN]
61 | | Cos(expr) -> (transformFexpr expr x) @ [COS]
62 | | Log(expr) -> (transformFexpr expr x) @ [LOG]
63 | | Exp(expr) -> (transformFexpr expr x) @ [EXP]
64 | | X -> [] // Not quite sure what to do with the X
65 |
66 |
67 | []
68 | type ``Chapter 06 exercise 8 Tests``() =
69 | []
70 | member x.``6.8 1. type Stack and interpretInstruction``() =
71 | test <@ interpretInstruction [1.0;2.0] ADD = [3.0] @>
72 | test <@ interpretInstruction [1.0;2.0] SUB = [1.0] @>
73 | test <@ interpretInstruction [1.0;2.0] MUL = [2.0] @>
74 | test <@ interpretInstruction [1.0;2.0] DIV = [2.0] @>
75 | test <@ interpretInstruction [1.0] SIN = [sin 1.0]@>
76 | test <@ interpretInstruction [] (PUSH(42.0)) = [42.0]@>
77 |
78 | []
79 | member x.``6.8 2. interpretProgram``() =
80 | test<@ interpretProgram [PUSH(3.0);PUSH(4.0);ADD] = 7.0 @>
81 | test<@ interpretProgram [PUSH(3.0);PUSH(4.0);SUB] = -1.0 @>
82 |
83 | []
84 | member x.``6.8 3. transformExpression``() =
85 | test <@ (transformFexpr (Add(Const(7.0), Const(8.0))) X) = [PUSH(7.0);PUSH(8.0);ADD] @>
86 | test <@
87 | (transformFexpr (Add(Mul(Const(7.0), Const(8.0)), Div(Const(9.0), Const(10.0)))) X)
88 | = [PUSH(7.0);PUSH(8.0);MUL;PUSH(9.0);PUSH(10.0);DIV;ADD]
89 | @>
90 |
--------------------------------------------------------------------------------
/Chapter_06_ex_4.fs:
--------------------------------------------------------------------------------
1 | module Chapter_06_ex_4
2 | #if INTERACTIVE
3 | #r "packages/Unquote.2.2.2/lib/net40/unquote.dll"
4 | #r "packages/NUnit.2.6.2/lib/nunit.framework.dll"
5 | #endif
6 | open System
7 | open System.Globalization
8 | open NUnit.Framework
9 | open Swensen.Unquote
10 |
11 | type BinTree<'a,'b> =
12 | | Leaf of 'a
13 | | Node of BinTree<'a,'b> * 'b * BinTree<'a,'b>;;
14 |
15 | // 6.4 1. leafValues
16 | let leafValues tree =
17 | let rec collectLeafValues tree collectedValues =
18 | match tree with
19 | | Leaf(leaf) -> leaf::collectedValues
20 | | Node(leftTree,_, rightTree) -> (collectLeafValues leftTree collectedValues)
21 | @ (collectLeafValues rightTree collectedValues)
22 |
23 | collectLeafValues tree []
24 | |> Set.ofList
25 |
26 | // 6.4 2. nodeValues
27 | let nodeValues tree =
28 | let rec collectNodeValues tree collectedValues =
29 | match tree with
30 | | Leaf(_) -> collectedValues
31 | | Node(left, value, right) -> value::(collectNodeValues left collectedValues)
32 | @ (collectNodeValues right collectedValues)
33 | collectNodeValues tree []
34 | |> Set.ofList
35 |
36 | // 6.4 3. values
37 | let values tree =
38 | let rec collectValues tree collectedLeafValues collectedNodeValues =
39 | match tree with
40 | | Leaf(leaf) -> (leaf::collectedLeafValues, collectedNodeValues)
41 | | Node(left, value, right) ->
42 | let leftValues = collectValues left collectedLeafValues collectedNodeValues
43 | let rightValues = collectValues right collectedLeafValues collectedNodeValues
44 | ((fst leftValues)@(fst rightValues), value::(snd leftValues)@(snd(rightValues)))
45 | let leafs, nodes = collectValues tree [] []
46 | (leafs |> Set.ofList, nodes |> Set.ofList)
47 |
48 | []
49 | type ``Chapter 06 exercise 4 Tests``() =
50 | []
51 | member x.``6.4 1. leafValues``() =
52 | test <@
53 | let tree = Node(
54 | Node(
55 | Leaf(1),
56 | "a",
57 | Node(
58 | Leaf(2),
59 | "b",
60 | Leaf(3)
61 | )
62 | ),
63 | "c",
64 | Leaf(3)
65 | )
66 | leafValues tree = Set[1;2;3]
67 | @>
68 |
69 | []
70 | member x.``6.4 2. nodeValues``() =
71 | test <@
72 | let tree = Node(
73 | Node(
74 | Leaf(1),
75 | "a",
76 | Node(
77 | Leaf(2),
78 | "b",
79 | Leaf(3)
80 | )
81 | ),
82 | "b",
83 | Leaf(3)
84 | )
85 | nodeValues tree = Set["a";"b"]
86 | @>
87 |
88 | []
89 | member x.``6.4 2. values``() =
90 | test <@
91 | let tree = Node(
92 | Node(
93 | Leaf(1),
94 | "a",
95 | Node(
96 | Leaf(2),
97 | "b",
98 | Leaf(3)
99 | )
100 | ),
101 | "b",
102 | Leaf(3)
103 | )
104 | values tree = (Set[1;2;3], Set["a";"b"])
105 | @>
106 |
--------------------------------------------------------------------------------
/Chapter_04_ex_11.fs:
--------------------------------------------------------------------------------
1 | module Chapter_04_ex_11
2 | #if INTERACTIVE
3 | #r "packages/Unquote.2.2.2/lib/net40/unquote.dll"
4 | #r "packages/FsUnit.1.2.1.0/lib/net40/FsUnit.NUnit.dll"
5 | #r "packages/NUnit.2.6.2/lib/nunit.framework.dll"
6 | #endif
7 | open System
8 | open NUnit.Framework
9 | open FsUnit
10 | open Swensen.Unquote
11 |
12 | // 4.11 bonus - check whether the list is actually a weak ascending list
13 | let checkWeakAscent weakList =
14 | let rec checkWeakAscent' weakList current =
15 | match weakList with
16 | | [] -> true
17 | | x::[] -> current <= x
18 | | x1::xs -> (current <= x1) && checkWeakAscent' xs x1
19 | checkWeakAscent' weakList Int32.MinValue
20 |
21 | // 4.11 - 1. Does not check the list for weak ascending list criteria
22 | let rec count weakList item =
23 | match weakList with
24 | | [] -> 0
25 | | x::[] -> if x = item then 1 else 0
26 | | x::xs -> (if x = item then 1 else 0) + count xs item
27 |
28 | // 4.11 - 2. Insert
29 | let rec insert weakList item =
30 | match weakList with
31 | | [] -> [item]
32 | | x::[] when item <= x -> [item] @ [x]
33 | | x::[] when item > x -> [x] @ [item]
34 | | x::xs when item <= x -> item::[x] @ xs
35 | | x::xs when item > x -> x::(insert xs item)
36 | | _ -> failwith "Incomplete match on %A" weakList
37 |
38 | // 4.11 - 3. intersect
39 | // Why does he want this as a tuple??
40 | //let rec intersect (list1, list2) =
41 | // match list1, list2 with
42 | // |
43 | //
44 | //test <@ intersect ([1;1;1;2;2], [1;1;2;4]) = [1;1;2] @>
45 | //test <@ intersect ([1;1;2;4], [1;1;1;2;2]) = [1;1;2] @>
46 |
47 | // 4.11 - 4. Plus
48 | let plus (list1, list2) =
49 | let rec plus' list resultlist =
50 | match list with
51 | | [] -> resultlist
52 | | x::xs -> insert resultlist x |> plus' xs
53 | plus' list2 list1
54 |
55 | // 4.11 - 5. Minus
56 | let minus (minuendList, subtrahendList) =
57 | let rec removeItem list itemToRemove resultList =
58 | match list with
59 | | [] -> resultList
60 | | x::[] when x = itemToRemove -> resultList
61 | | x::xs when x = itemToRemove -> resultList @ xs
62 | | x::xs -> resultList @ [x] @ removeItem xs itemToRemove resultList
63 | let rec removeList listToRemove resultlist =
64 | match listToRemove with
65 | | [] -> resultlist
66 | | x::xs -> removeList xs (removeItem resultlist x [])
67 | removeList subtrahendList minuendList
68 |
69 |
70 | []
71 | type ``Chapter_04_ex_11_Tests``() =
72 | []
73 | member x.``4.11 bonus checkWeakAscent``() =
74 | checkWeakAscent [] |> should equal true
75 | checkWeakAscent [1] |> should equal true
76 | checkWeakAscent [1;1] |> should equal true
77 | checkWeakAscent [1;2] |> should equal true
78 | checkWeakAscent [1;1;1] |> should equal true
79 | checkWeakAscent [1;2;1] |> should equal false
80 | checkWeakAscent [1;2;2] |> should equal true
81 | checkWeakAscent [1;2;3] |> should equal true
82 | checkWeakAscent [2;2;3] |> should equal true
83 | checkWeakAscent [3;2] |> should equal false
84 | checkWeakAscent [3;2;3] |> should equal false
85 |
86 | []
87 | member x.``4.11 1. count recursive``() =
88 | count [] 1 |> should equal 0
89 | count [1] 0 |> should equal 0
90 | count [1] 1 |> should equal 1
91 | count [1;2;3] 1 |> should equal 1
92 | count [1;1;3] 1 |> should equal 2
93 |
94 | []
95 | member x.``4.11 2. insert``() =
96 | test <@ insert [] 1 = [1] @>
97 | test <@ insert [1] 0 = [0;1] @>
98 | test <@ insert [1] 1 = [1;1] @>
99 | test <@ insert [1] 2 = [1;2] @>
100 | test <@ insert [1;2;3] 1 = [1;1;2;3] @>
101 | test <@ insert [1;1;3] 4 = [1;1;3;4] @>
102 | test <@ insert [1;1;3] 2 = [1;1;2;3] @>
103 |
104 | []
105 | member x.``4.11 3. intersect``() =
106 | //test <@ intersect ([1;1;1;2;2], [1;1;2;4]) = [1;1;2] @>
107 | //test <@ intersect ([1;1;2;4], [1;1;1;2;2]) = [1;1;2] @>
108 | test <@ "Not implemented" = "" @>
109 |
110 | []
111 | member x.``4.11 4. plus``() =
112 | test <@ plus([1;1;2], [1;2;4]) = [1;1;1;2;2;4]@>
113 | test <@ plus([1;2;4], [1;1;2]) = [1;1;1;2;2;4]@>
114 | test <@ plus([1;3;5], [2;4;6]) = [1;2;3;4;5;6]@>
115 |
116 | []
117 | member x.``4.11 5. minus``() =
118 | test <@ minus([1;1;1;2;2],[1;1;2;3]) = [1;2] @>
119 | test <@ minus([1;1;1;2;2;4],[1;1;2;3]) = [1;2;4] @>
120 |
--------------------------------------------------------------------------------
/Chapter_01.fs:
--------------------------------------------------------------------------------
1 | module Chapter_01
2 |
3 |
4 | // 1.1 - well, even to a beginner this is child's stuff ;)
5 | let g n =
6 | n + 4
7 |
8 | // 1.2
9 | let h1 x y =
10 | System.Math.Sqrt(x*x + y*y)
11 |
12 | // Why is it necessary to give a type here??
13 | // Well, the reason is that sqrt is only defined for the types float and double.
14 | // Think of it as an extension method to those types. Since there are two types
15 | // to choose from, F# cannot possibly figure out the right one. It therefore
16 | // falls back to the default inferred type: int - which means that it thinks
17 | // that both x and y are ints, and sqrt is not defined for int. Why, then,
18 | // it is enough to add a return type (: float), I'm not at all sure of, though...
19 | let h2 x y : float =
20 | sqrt(x*x + y*y)
21 |
22 | // 1.3
23 | // Note! One thing that confuses me here is the implicit parameter! I started
24 | // writing:
25 | // let gf n = function - which really gives some rather non-obvious results
26 | // (see gfn below). The implicit parameter the book totally forgets to mention.
27 | let gf = function
28 | | x -> x + 4
29 |
30 | let gfn n = function
31 | | x-> x + 4
32 |
33 | let hf1 = function
34 | | (x, y) -> System.Math.Sqrt(x*x + y*y)
35 |
36 | // Again why necessary to give the type? Same reason as in 1.2 above.
37 | let hf2 = function
38 | | (x:float, y:float) -> sqrt(x*x + y*y)
39 |
40 | // 1.4
41 | // How to avoid the incomplete matches warning? Well, F# does not take the
42 | // when clauses into consideration, when figuring out what matches and what
43 | // does not.
44 | // Please note that this implementation will do a stackoverflov on negative
45 | // values and on large values, since it is not tail-recursive
46 | let rec f14 = function
47 | | 0 -> 0
48 | | 1 -> 1
49 | | n when n < 0 -> 0
50 | | n when n > 0 -> n + (n-1 |> f14)
51 | // f n = 10
52 |
53 | // To avoid the incomplete matches warning it helps to have understood the
54 | // assignment correctly. The following implementations thanks to
55 | // Ramón Soto Mathiesen:
56 |
57 | let rec f = function // stackoverflow issue (on negative and large values)
58 | | 1 -> 1
59 | | n -> n + f (n-1)
60 |
61 | let f' n = // tail-recursive (chapter 9)
62 | let rec f'' a = function
63 | | 1 -> (1+a)
64 | | n -> f'' (a+n) (n-1)
65 | f'' 0 n
66 |
67 | let f'' n = // cps - continuation passing style (chapter 9)
68 | let rec f''' k = function
69 | | 1 -> k 1
70 | | n -> f''' (fun x -> k (n+x)) (n-1)
71 | f''' id n
72 |
73 | // 1.5 - The naive implementation, which has infinte recursion on negative and
74 | // large values and of course is horribly inefficient, since it calculates the
75 | // values twice.
76 | let rec fib = function
77 | | 0 -> 0
78 | | 1 -> 1
79 | | n -> (n-1 |> fib) + (n-2 |> fib)
80 | // | fib (n-1) + fib (n-2) // alternative way of writing the recursive call
81 |
82 | // The following implementations by Ramón Soto Mathiesen:
83 |
84 | // chapter 9
85 | let fib' n = // cps - continuation passing style (still stackoverflow issue)
86 | let rec fib'' k = function
87 | | 0 -> k 0
88 | | 1 -> k 1
89 | | n -> fib''(fun x -> fib''(fun y -> k(x+y)) (n-2)) (n-1)
90 | fib'' id n
91 |
92 | let rec fib'' n = // tail-recursive with to accs (chapter 9)
93 | let rec fib''' a1 a2 = function
94 | | 0 -> 0
95 | | 1 -> a1 + a2
96 | | n -> fib''' a2 (a1 + a2) (n - 1)
97 | fib''' 1 0 n
98 |
99 | type ContinuationBuilder() = // chapter 12
100 | member b.Bind(x, f) = fun k -> x (fun x -> f x k)
101 | member b.Return x = fun k -> k x
102 | member b.ReturnFrom x = x
103 | let cont = ContinuationBuilder()
104 | let fib''' n = // cps with monads (still stackoverflow issue)
105 | let rec fib'''' n = cont {
106 | match n with
107 | | 0 -> return 0
108 | | 1 -> return 1
109 | | n ->
110 | let! x = fib''''(n-1)
111 | let! y = fib''''(n-2)
112 | return x + y}
113 | fib'''' n id
114 |
115 |
116 | // 1.6 - stackoverflow issues
117 | let rec sum (m, n) =
118 | match (m, n) with
119 | | (m, 0) -> m
120 | | (m, n) -> (m + n) + sum(m, n-1)
121 |
122 | // The following implementation by Ramón Soto Mathiesen:
123 | let sum' (m,n) = // tail-recursive
124 | let rec sum'' a = function
125 | | (m,0) -> (m+a)
126 | | (m,n) -> sum'' (a+m+n) (m,n-1)
127 | sum'' 0 (m,n)
128 |
129 |
130 | // 1.7 - both fact and power has obvious stackoverflow issues.
131 | let rec fact = function
132 | | 0 -> 1
133 | | n -> n * fact(n-1)
134 |
135 | let rec power = function
136 | | (x, 0) -> 1.0
137 | | (x, n) -> x* power(x, n-1)
138 |
139 |
140 | let t1 = (System.Math.PI, fact -1) : float * int
141 |
142 | let t2 = fact(fact 4): int
143 |
144 | let t3 = power(System.Math.PI, fact 2) : float
145 |
146 | let t4 = (power, fact) : (float * int -> float) * (int -> int)
147 |
148 |
149 | // 1.8
150 | let a = 5
151 | // As a curiosum, try writing: let f18 a = a +1
152 | // It gives a rather unexpected result.
153 | let f18 a = a + 1
154 |
155 | // (using g18 (underscore) because g is already used above)
156 | let g18 b = (f b) + a
157 |
158 | // | a |-> 5 |
159 | // env = | f18 |-> "the add one function" |
160 | // | g18 |-> "the add six function" |
161 |
162 | // f18 3
163 | // ~> 3 + 1
164 | // ~> 4
165 |
166 | // g18 3
167 | // ~> (f18 3) + a
168 | // ~> (3 + 1) + a
169 | // ~> 4 + 5
170 | // ~> 9
171 |
--------------------------------------------------------------------------------
/Chapter_02_Tests.fs:
--------------------------------------------------------------------------------
1 | module Chapter_02_Tests
2 | open System
3 | open NUnit.Framework
4 | open FsUnit
5 | open Chapter_02
6 |
7 | []
8 | type ``Chapter_02_Tests``() =
9 |
10 | []
11 | member x.``2.1``() =
12 | f 5 |> should equal false
13 | f 6 |> should equal true
14 | f 15 |> should equal false
15 | f 24 |> should equal true
16 | f 27 |> should equal true
17 | f 29 |> should equal false
18 | f 30 |> should equal false
19 |
20 | member x.``powTester`` powf =
21 | powf "a" -1 |> should equal "" // I've chosen to define it like this
22 | powf "a" 0 |> should equal ""
23 | powf "a" 1 |> should equal "a"
24 | powf "a" 2 |> should equal "aa"
25 | powf "a" 42 |> should equal "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
26 | powf "" 0 |> should equal ""
27 | powf "" 1 |> should equal ""
28 | powf "" 2 |> should equal ""
29 | powf "" 42 |> should equal ""
30 |
31 | []
32 | member x.``2.2_recursive``() =
33 | x.powTester pow
34 |
35 | []
36 | member x.``2.2_stringBuilder``() =
37 | x.powTester powWithBuilder
38 |
39 | []
40 | member x.``2.2_stringConcat``() =
41 | x.powTester powWithStringConcat
42 |
43 |
44 | []
45 | member x.``2.3 isIthChar``() =
46 | isIthChar ("abcdef", 2, 'c') |> should equal true
47 | isIthChar ("abcdef", 2, 'd') |> should equal false
48 | isIthChar ("abcdef", 17, 'g') |> should equal false
49 |
50 | []
51 | member x.``2.4 occFromIth``() =
52 | occFromIth ("abcabcabc", -1, 'a') |> should equal 0
53 | occFromIth ("abcabcabc", 0, 'a') |> should equal 3
54 | occFromIth ("abcabcabc", 5, 'a') |> should equal 1
55 | occFromIth ("abcabcabc", 15, 'a') |> should equal 0
56 |
57 | []
58 | member x.``2.5 occInString``() =
59 | occInString ("abcbcecde", 'a') |> should equal 1
60 | occInString ("abcbcecde", 'b') |> should equal 2
61 | occInString ("abcbcecde", 'c') |> should equal 3
62 | occInString ("abcbcecde", 'e') |> should equal 2
63 | occInString ("abcbcecde", 'f') |> should equal 0
64 |
65 | []
66 | member x.``2.6 notDivisible``() =
67 | notDivisible (-2, -5) |> should equal true
68 | notDivisible (2, 5) |> should equal true
69 | notDivisible (9, 3) |> should equal false
70 |
71 | []
72 | member x.``2.7 1. test``() =
73 | test(4, 6, 2) |> should equal false
74 | test(6, 9, 5) |> should equal true
75 |
76 | test_if(4, 6, 2) |> should equal false
77 | test_if(6, 9, 5) |> should equal true
78 |
79 | []
80 | member x.``2.7 2. prime``() =
81 | prime 1 |> should equal true
82 | prime 2 |> should equal true
83 | prime 3 |> should equal true
84 | prime 4 |> should equal false
85 | prime 5 |> should equal true
86 | prime 6 |> should equal false
87 | prime 7 |> should equal true
88 | prime 8 |> should equal false
89 | prime 9 |> should equal false
90 | prime 10 |> should equal false
91 | prime 23 |> should equal true
92 |
93 | []
94 | member x.``2.7 3. nextPrime``() =
95 | nextPrime 1 |> should equal 2
96 | nextPrime 2 |> should equal 3
97 | nextPrime 3 |> should equal 5
98 | nextPrime 4 |> should equal 5
99 | nextPrime 5 |> should equal 7
100 | nextPrime 6 |> should equal 7
101 | nextPrime 7 |> should equal 11
102 | nextPrime 8 |> should equal 11
103 | nextPrime 9 |> should equal 11
104 | nextPrime 10 |> should equal 11
105 | nextPrime 23 |> should equal 29
106 |
107 | []
108 | member x.``2.8 binomial coefficients``() =
109 | bin(0,0) |> should equal 1
110 | bin(1,0) |> should equal 1
111 | bin(1,1) |> should equal 1
112 | bin(2,0) |> should equal 1
113 | bin(2,1) |> should equal 2
114 | bin(2,2) |> should equal 1
115 | bin(3,0) |> should equal 1
116 | bin(3,1) |> should equal 3
117 | bin(3,2) |> should equal 3
118 | bin(3,3) |> should equal 1
119 | bin(4,0) |> should equal 1
120 | bin(4,1) |> should equal 4
121 | bin(4,2) |> should equal 6
122 | bin(4,3) |> should equal 4
123 | bin(4,4) |> should equal 1
124 | bin(5,0) |> should equal 1
125 | bin(5,1) |> should equal 5
126 | bin(5,2) |> should equal 10
127 | bin(5,3) |> should equal 10
128 | bin(5,4) |> should equal 5
129 | bin(5,5) |> should equal 1
130 |
131 | []
132 | member x.``2.11 VAT``() =
133 | VAT 10 100.0 |> should equal 110.0
134 | VAT 0 1.0 |> should equal 1.0
135 |
136 | []
137 | member x.``2.11 unVAT``() =
138 | unVAT 10 110.0 |> should (equalWithin 0.01) 100.0//be (greaterThan 99.99)
139 | unVAT 0 1.0 |> should equal 1.0
140 | unVAT 10 (VAT 10 100.0) |> should (equalWithin 0.01) 100.0 //be (greaterThan 99.99)
141 | unVAT 0 (VAT 0 1.0) |> should equal 1.0
142 |
143 | []
144 | member x.``2.12 min(f)``() =
145 | min(fun n -> n % 2) |> should equal 2
146 | // Disabled - way to slow ;)
147 | // min(fun n -> if n = 0 then 0 else 1) |> should equal 0
148 | min(fun n -> n % 10000) |> should equal 10000
149 |
--------------------------------------------------------------------------------
/Chapter_02.fs:
--------------------------------------------------------------------------------
1 | module Chapter_02
2 | open System
3 |
4 | // 2.1 - again: remember the implicit parameter
5 | let f = function
6 | | n when n % 5 = 0 -> false
7 | | n when n % 2 = 0 -> true
8 | | n when n % 3 = 0 -> true
9 | | _ -> false
10 |
11 | // 2.2 - here a recursive version
12 | // String.Concat(IEnumerable values) could also be used
13 | let rec pow s n =
14 | match n with
15 | | x when x <= 0 -> "" // I choose to define it like this
16 | | 1 -> s
17 | | x -> s + pow s (n-1)
18 |
19 | // 2.2 - a version using StringBuilder - preliminary timings suggest that this
20 | // version is by far the most performant
21 | let powWithBuilder (s: string) n =
22 | let builder = System.Text.StringBuilder()
23 | for count = 1 to n do
24 | builder.Append(s) |> ignore
25 | builder.ToString()
26 |
27 | // 2.2 - a version using String.Concat - seems to be slowest
28 | let powWithStringConcat s n =
29 | String.Concat(seq { for i in 1 .. n do yield s })
30 |
31 | // 2.3 - checking for an index outside the range could either return false
32 | // (as here) or throw an ArgumentOutOfRangeException.
33 | // Note here, that it is necessary to explicitly define the type for s
34 | let isIthChar ((s:string), index, ch) =
35 | if (index < 0 || index >= s.Length) then
36 | false; // throw ArgumentException("Should be inside Length of s", "index")
37 | else
38 | s.[index] = ch
39 |
40 | // 2.4 - indices outside the range results in 0
41 | // Using s.Substring for obtaining the part of the string from index and onwards.
42 | let occFromIth(s: string, index, ch) =
43 | if (index < 0 || index >= s.Length) then
44 | 0
45 | else
46 | s.Substring index
47 | |> Seq.filter(fun charAtIndex -> charAtIndex = ch)
48 | |> Seq.length
49 |
50 | // 2.5 - Reusing our occFromIth function from above.
51 | let occInString(s: string, ch) =
52 | occFromIth(s, 0, ch)
53 |
54 | // 2.6 - If d < n then d will never be divisible by n
55 | let notDivisible (d, n) =
56 | if (abs(d) < abs(n)) then
57 | true
58 | else
59 | not (d % n = 0)
60 |
61 | // 2.7 1. - with pattern matching
62 | let rec test(a, b, c) =
63 | match (a, b) with
64 | |_ when a > b -> failwith(String.Format("a should <= b: {0} <= {1}", a, b))
65 | |_ when a < b -> notDivisible(a, c) && test(a + 1, b, c)
66 | |_ -> notDivisible(a, c)
67 |
68 | // or using ifs - far less readable
69 | let rec test_if(a, b, c) =
70 | if a > b then
71 | failwith(String.Format("a should <= b: {0} <= {1}", a, b))
72 | else
73 | if a < b then
74 | notDivisible(a, c) && test(a + 1, b, c)
75 | else
76 | notDivisible(a, c)
77 |
78 | // 2.7 2.
79 | // n is a prime if it cannot be divided by any integer from 2 to sqrt(n)
80 | // I think the book intends us to use the test(a,b,c) function above, but it is
81 | // defined incorrectly - a correctly defined should look like this (a and c is reversed):
82 | let rec test_prime(a, b, c) =
83 | match (a, b) with
84 | |_ when a > b -> failwith(String.Format("a should <= b: {0} <= {1}", a, b))
85 | |_ when a < b -> notDivisible(c, a) && test_prime(a + 1, b, c)
86 | |_ -> notDivisible(c, a)
87 |
88 |
89 | // The matches with 1, 2, and 3 are to avoid b < a when using sqrt.
90 | // Can the "(float)n |> sqrt |> Math.Floor |> (int)" be written more intelligible?
91 | let prime n =
92 | match n with
93 | | 1 -> true
94 | | 2 -> true
95 | | 3 -> true
96 | | _ when n < 1 -> false
97 | | _ -> test_prime(2, (float)n |> sqrt |> Math.Floor |> (int) , n)
98 |
99 | // 2.7 3.
100 | let rec nextPrime n =
101 | let isPrime = prime (n + 1)
102 | if isPrime then
103 | n + 1
104 | else
105 | nextPrime (n + 1)
106 |
107 | // 2.8 Binomial coefficients
108 | // This version is not tail-recursive, which will pose a problem for
109 | // bigger n's and k's
110 | // Furthermore it will calculate a lot of the numbers twice (I think...)
111 | let rec bin(n, k) =
112 | match (n, k) with
113 | | (row, 0) -> 1
114 | | (row, col) when col = n -> 1
115 | | (row, col) -> bin(n - 1, k - 1) + bin(n - 1, k)
116 |
117 | // 2.9
118 | let rec f_ = function
119 | | (0, y) -> y
120 | | (x, y) -> f_(x-1, x*y)
121 |
122 | // 1. The inferred type is int*int -> int
123 | // 2. The function terminates for values (x, y) where x >= 0
124 | // 3.
125 | // f_(2, 3)
126 | // ~> f_(2-1, 2*3)
127 | // ~> f_(1, 6)
128 | // ~> f_(1-1, 1*6)
129 | // ~> f_(0, 6)
130 | // ~> 6
131 |
132 | // f_(3, 2)
133 | // ~> f_(3-1, 3*2)
134 | // ~> f_(2, 6)
135 | // ~> f_(2-1, 2*6)
136 | // ~> f_(1, 12)
137 | // ~> f_(1-1, 1*12)
138 | // ~> f_(0, 12)
139 | // ~> 12
140 |
141 | // f_(6, 6)
142 | // ~> f_(6-1, 6*6)
143 | // ~> f_(5, 36)
144 | // ~> f_(5-1, 5*36)
145 | // ~> f_(4, 180)
146 | // ~> f_(4-1, 4*180)
147 | // ~> f_(3, 720)
148 | // ~> f_(3-1, 3*720)
149 | // ~> f_(2, 2160)
150 | // ~> f_(2-1, 2*2160)
151 | // ~> f_(1, 4320)
152 | // ~> f_(1-1, 1*4320)
153 | // ~> f_(0, 4320)
154 | // ~> 4320
155 |
156 |
157 | // 4. f_(x, y) = ??? Any mathematicians who can figure out what the answer
158 | // should be?
159 |
160 |
161 | // 2.10
162 | let test_(c, e) = if c then e else 0;;
163 | // 1. The inferred type is bool*int -> int
164 | // 2. This seems to result in a StackOverflowException (if the fact function is
165 | // naively implemented - which the version from chapter 1 is)
166 | // It does this, because fact(-1) is evaluated before calling test_
167 | open Chapter_01 // access the fact function
168 | let ``2.10 2. result`` = test_(false, fact(-1))
169 |
170 | // 3. This, on the other hand, succeeds:
171 | // It does this, because fact -1 is only evaluated/executed in the true branch
172 | // of the if, which of course is never hit here, due to the "if false then".
173 | let ``2.10 3. result`` = if false then fact -1 else 0
174 |
175 | // 2.11 VAT / unVAT
176 | let VAT n x = x + x * float n/100.0
177 |
178 | let unVAT n x = x / ((100.0 + float n) / 100.0)
179 |
180 | // 2.12 min(f n)
181 | // This is obviously a horribly ineffecient way to do this - but it cannot be done any
182 | // different, can it???
183 | let min f =
184 | seq { for n in 1 .. Int32.MaxValue do yield n}
185 | |> Seq.find (fun n -> f n = 0)
186 |
187 | // 2.13 curry/uncurry
188 | // I personally couldn't figure out what this exercise wants me to do...
189 | // Thanks to Rune Ibsen for this:
190 | let curry f = fun a -> fun b -> f (a,b)
191 | let uncurry f = fun (a,b) -> f a b
--------------------------------------------------------------------------------
/FunctionalProgrammingUsingFSharp.fsproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | 2.0
8 | 53A0AE05-0A65-49AA-9606-4C7973AD96E4
9 | Exe
10 | FunctionalProgrammingUsingFSharp
11 | FunctionalProgrammingUsingFSharp
12 | v4.5
13 | FunctionalProgrammingUsingFSharp
14 | 12.0.0
15 |
16 |
17 | true
18 | full
19 | false
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | 3
24 | AnyCPU
25 | bin\Debug\FunctionalProgrammingUsingFSharp.XML
26 | true
27 |
28 |
29 | pdbonly
30 | true
31 | true
32 | bin\Release\
33 | TRACE
34 | 3
35 | AnyCPU
36 | bin\Release\FunctionalProgrammingUsingFSharp.XML
37 | true
38 |
39 |
40 |
41 | packages\FsUnit.1.2.1.0\Lib\Net40\FsUnit.NUnit.dll
42 |
43 |
44 |
45 | True
46 |
47 |
48 | packages\NUnit.2.6.2\lib\nunit.framework.dll
49 |
50 |
51 |
52 |
53 |
54 | packages\Unquote.2.2.2\lib\net40\Unquote.dll
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 | 11
118 |
119 |
120 |
127 |
--------------------------------------------------------------------------------
/Chapter_06_ex_3.fs:
--------------------------------------------------------------------------------
1 | module Chapter_06_ex_3
2 | #if INTERACTIVE
3 | #r "packages/Unquote.2.2.2/lib/net40/unquote.dll"
4 | #r "packages/NUnit.2.6.2/lib/nunit.framework.dll"
5 | #endif
6 | open System
7 | open System.Globalization
8 | open NUnit.Framework
9 | open Swensen.Unquote
10 |
11 | // 6.3 - better toString
12 | type Fexpr = | Const of float
13 | | X // What is this doing??
14 | | Add of Fexpr * Fexpr
15 | | Sub of Fexpr * Fexpr
16 | | Mul of Fexpr * Fexpr
17 | | Div of Fexpr * Fexpr
18 | | Sin of Fexpr
19 | | Cos of Fexpr
20 | | Log of Fexpr
21 | | Exp of Fexpr
22 |
23 | // The original toString
24 | let rec toString = function
25 | | Const x -> string x
26 | | X -> "x"
27 | | Add(fe1,fe2) -> "(" + (toString fe1) + ")"
28 | + " + " + "(" + (toString fe2) + ")"
29 | | Sub(fe1,fe2) -> "(" + (toString fe1) + ")"
30 | + " - " + "(" + (toString fe2) + ")"
31 | | Mul(fe1,fe2) -> "(" + (toString fe1) + ")"
32 | + " * " + "(" + (toString fe2) + ")"
33 | | Div(fe1,fe2) -> "(" + (toString fe1) + ")"
34 | + " / " + "(" + (toString fe2) + ")"
35 | | Sin fe -> "(sin " + (toString fe) + ")"
36 | | Cos fe -> "(cos " + (toString fe) + ")"
37 | | Log fe -> "(log " + (toString fe) + ")"
38 | | Exp fe -> "(exp " + (toString fe) + ")";;
39 |
40 | // It takes a LOT of patterns to complete this! (And a lot of tests to verify...)
41 | // It would be possible to reduce the amount of patterns by using when expressions
42 | // but I actually prefer patterns. I think I have all the permutations covered ;9
43 | let rec betterToString = function
44 | | Const value -> String.Format(CultureInfo.InvariantCulture, "{0:0.0######}", value)
45 | | X -> "x"
46 |
47 |
48 | | Add((Mul(_,_) as mul1), (Mul(_,_) as mul2)) -> "(" + (betterToString mul1) + ")"
49 | + " + " + "(" + (betterToString mul2) + ")"
50 | | Add((Div(_,_) as div1), (Div(_,_) as div2)) -> "(" + (betterToString div1) + ")"
51 | + " + " + "(" + (betterToString div2) + ")"
52 | | Add((Mul(_,_) as mul), (Div(_,_) as div)) -> "(" + (betterToString mul) + ")"
53 | + " + " + "(" + (betterToString div) + ")"
54 | | Add((Div(_,_) as div), (Mul(_,_) as mul)) -> "(" + (betterToString div) + ")"
55 | + " + " + "(" + (betterToString mul) + ")"
56 | | Add((Mul(_,_) as mul), fe2) -> "(" + (betterToString mul) + ")"
57 | + " + " + (betterToString fe2)
58 | | Add((Div(_,_) as div), fe2) -> "(" + (betterToString div) + ")"
59 | + " + " + (betterToString fe2)
60 | | Add(fe1, (Mul(_,_) as mul)) -> (betterToString fe1)
61 | + " + " + "(" + (betterToString mul) + ")"
62 | | Add(fe1, (Div(_,_) as div)) -> (betterToString fe1)
63 | + " + " + "(" + (betterToString div) + ")"
64 | | Add(fe1,fe2) -> (betterToString fe1) + " + " + (betterToString fe2)
65 |
66 |
67 | | Sub((Mul(_,_) as mul1), (Mul(_,_) as mul2)) -> "(" + (betterToString mul1) + ")"
68 | + " - " + "(" + (betterToString mul2) + ")"
69 | | Sub((Div(_,_) as div1), (Div(_,_) as div2)) -> "(" + (betterToString div1) + ")"
70 | + " - " + "(" + (betterToString div2) + ")"
71 | | Sub((Mul(_,_) as mul), (Div(_,_) as div)) -> "(" + (betterToString mul) + ")"
72 | + " - " + "(" + (betterToString div) + ")"
73 | | Sub((Div(_,_) as div), (Mul(_,_) as mul)) -> "(" + (betterToString div) + ")"
74 | + " - " + "(" + (betterToString mul) + ")"
75 | | Sub((Mul(_,_) as mul), fe2) -> "(" + (betterToString mul) + ")"
76 | + " - " + (betterToString fe2)
77 | | Sub((Div(_,_) as div), fe2) -> "(" + (betterToString div) + ")"
78 | + " - " + (betterToString fe2)
79 | | Sub(fe1, (Mul(_,_) as mul)) -> (betterToString fe1)
80 | + " - " + "(" + (betterToString mul) + ")"
81 | | Sub(fe1, (Div(_,_) as div)) -> (betterToString fe1)
82 | + " - " + "(" + (betterToString div) + ")"
83 | | Sub(fe1,fe2) -> (betterToString fe1) + " - " + (betterToString fe2)
84 |
85 |
86 | | Mul((Add(_, _) as add1), (Add(_, _) as add2)) -> "(" + (betterToString add1) + ")"
87 | + " * " + "(" + (betterToString add2) + ")"
88 | | Mul((Sub(_, _) as sub1), (Sub(_, _) as sub2)) -> "(" + (betterToString sub1) + ")"
89 | + " * " + "(" + (betterToString sub2) + ")"
90 | | Mul((Add(_, _) as add), (Sub(_, _) as sub)) -> "(" + (betterToString add) + ")"
91 | + " * " + "(" + (betterToString sub) + ")"
92 | | Mul((Sub(_, _) as sub), (Add(_, _) as add)) -> "(" + (betterToString sub) + ")"
93 | + " * " + "(" + (betterToString add) + ")"
94 | | Mul(Add(_, _) as add, fe2) -> "(" + (betterToString add) + ")"
95 | + " * " + (betterToString fe2)
96 | | Mul(Sub(_, _) as sub, fe2) -> "(" + (betterToString sub) + ")"
97 | + " * " + (betterToString fe2)
98 | | Mul(fe1, (Add(_, _) as add)) -> (betterToString fe1)
99 | + " * " + "(" + (betterToString add) + ")"
100 | | Mul(fe1, (Sub(_, _) as sub)) -> (betterToString fe1)
101 | + " * " + "(" + (betterToString sub) + ")"
102 | | Mul(fe1,fe2) -> "(" + (betterToString fe1) + ")"
103 | + " * " + "(" + (betterToString fe2) + ")"
104 |
105 | | Div((Add(_, _) as add1), (Add(_, _) as add2)) -> "(" + (betterToString add1) + ")"
106 | + " / " + "(" + (betterToString add2) + ")"
107 | | Div((Sub(_, _) as sub1), (Sub(_, _) as sub2)) -> "(" + (betterToString sub1) + ")"
108 | + " / " + "(" + (betterToString sub2) + ")"
109 | | Div((Add(_, _) as add), (Sub(_, _) as sub)) -> "(" + (betterToString add) + ")"
110 | + " / " + "(" + (betterToString sub) + ")"
111 | | Div((Sub(_, _) as sub), (Add(_, _) as add)) -> "(" + (betterToString sub) + ")"
112 | + " / " + "(" + (betterToString add) + ")"
113 | | Div(Add(_, _) as add, fe2) -> "(" + (betterToString add) + ")"
114 | + " / " + (betterToString fe2)
115 | | Div(Sub(_, _) as sub, fe2) -> "(" + (betterToString sub) + ")"
116 | + " / " + (betterToString fe2)
117 | | Div(fe1, (Add(_, _) as add)) -> (betterToString fe1)
118 | + " / " + "(" + (betterToString add) + ")"
119 | | Div(fe1, (Sub(_, _) as sub)) -> (betterToString fe1)
120 | + " / " + "(" + (betterToString sub) + ")"
121 | | Div(fe1,fe2) -> "(" + (betterToString fe1) + ")"
122 | + " / " + "(" + (betterToString fe2) + ")"
123 | | Sin(Const(_) as c) -> "sin " + (betterToString c)
124 | | Sin(X as x) -> "sin " + (betterToString x)
125 | | Sin fe -> "sin" + "(" + (betterToString fe) + ")"
126 |
127 | | Cos(Const(_) as c) -> "cos " + (betterToString c)
128 | | Cos(X as x) -> "cos " + (betterToString x)
129 | | Cos fe -> "cos" + "(" + (betterToString fe) + ")"
130 |
131 | | Log(Const(_) as c) -> "log " + (betterToString c)
132 | | Log(X as x) -> "log " + (betterToString x)
133 | | Log fe -> "log" + "(" + (betterToString fe) + ")"
134 |
135 | | Exp(Const(_) as c) -> "exp " + (betterToString c)
136 | | Exp(X as x) -> "exp " + (betterToString x)
137 | | Exp fe -> "exp" + "(" + (betterToString fe) + ")"
138 |
139 | []
140 | type ``Chapter 06 exercise 3 Tests``() =
141 | []
142 | member x.``6.3 toString without uncessesary parenthesis``() =
143 | test <@ betterToString (Mul(Add(Const(2.0), Const(3.0)), Sub(Const(4.0), Const(5.0))))
144 | = "(2.0 + 3.0) * (4.0 - 5.0)" @>
145 | test <@ betterToString (Mul(Sub(Const(2.0), Const(3.0)), Add(Const(4.0), Const(5.0))))
146 | = "(2.0 - 3.0) * (4.0 + 5.0)" @>
147 |
148 | test <@ betterToString (Mul(Sin(Const(3.0)), Sub(Const(4.0), Const(5.0))))
149 | = "sin 3.0 * (4.0 - 5.0)" @>
150 | test <@ betterToString (Mul(Sub(Const(2.0), Const(3.0)), Sin(Const(4.0))))
151 | = "(2.0 - 3.0) * sin 4.0" @>
152 |
153 | test <@ betterToString (Div(Add(Const(2.0), Const(3.0)), Sub(Const(4.0), Const(5.0))))
154 | = "(2.0 + 3.0) / (4.0 - 5.0)" @>
155 | test <@ betterToString (Div(Sub(Const(2.0), Const(3.0)), Add(Const(4.0), Const(5.0))))
156 | = "(2.0 - 3.0) / (4.0 + 5.0)" @>
157 |
158 | test <@ betterToString (Sin(Add(Const(2.0), Const(3.0)))) = "sin(2.0 + 3.0)" @>
159 |
--------------------------------------------------------------------------------
/packages/Unquote.2.2.2/lib/sl4/Unquote.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Unquote
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | Exception used to signal assertion failure to be caught by any exception framework
17 | (used when not NUnit or xUnit.net or when compiled for Silverlight)
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | Exception used to distinguish an error in the quotation evaluation engine.
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | Test wether the given expr fails with the given expected exception (or a subclass thereof) when the additional assertion on the exception object holds.
55 |
56 |
57 |
58 |
59 | Test wether the given expr fails with the given expected exception (or a subclass thereof).
60 |
61 |
62 |
63 |
64 | Evaluate the given boolean expression: if false output incremental eval steps using
65 | 1) stdout if fsi mode
66 | 2) framework fail methods if Xunit or Nunit present
67 | 3) System.Exception if release mode.
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 | Functions and values public inline Operator functions rely on (and therefore must be public,
97 | even though we do not want to expose them publically).
98 |
99 |
100 |
101 |
102 | Operators on Expr and Expr<'a> for performing unit test assertions.
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 | aty is the arg type, bty is the return type, x is the arg
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 | name is the name of the unary op method, aty is the arg type, x is the arg
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 | Binary ops of the form 'a->int->'a
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 | name is the name of the method, aty is the type of the first arg, bty is the type of the second arg,
258 | x is the first arg, y is the second arg.
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 | The purpose of these operator implementations is two fold 1) many F# operators do not include dynamic impls,
321 | so we must give them. 2) even those operators which are given dynamic impls do not perform well since they
322 | need to be accessed via reflection, so we give "native" impls here.
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 | "reraise" the given exception, preserving the stacktrace (e.g. for InnerExceptions of TargetInvocation exceptions)
376 |
377 |
378 |
379 |
380 | Strip possibly nested target invocation exception
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 | The F#-style signature. Note: this property is out-of-place in this assembly and may be moved elsewhere in future versions.
389 |
390 |
391 |
392 |
393 | Determine whether this expression is reduced.
394 |
395 |
396 |
397 |
398 | Convert the given expression to a list of all of its Reduce steps in order.
399 |
400 |
401 |
402 |
403 | Convert this expression with the given variable environment to a list of all of its Reduce steps in order.
404 |
405 |
406 |
407 |
408 | Reduce this expression by one step: convert each branch of the given expression to a Value expression of its
409 | evaluation if each sub-branch of the branch is reduced.
410 | If this expression is already reduced, or cannot be reduced, returns itself.
411 |
412 |
413 |
414 |
415 | Reduce this expression by one step with the given variable environment: convert each branch of the given expression to a Value expression of its
416 | evaluation if each sub-branch of the branch is reduced.
417 | If this expression is already reduced, or cannot be reduced, returns itself.
418 |
419 |
420 |
421 |
422 | Decompile this expression to its source code representation. Sub-expressions which are
423 | not currently supported will fallback on the default Expr.ToString() implementation.
424 |
425 |
426 |
427 |
428 | Evaluate this untyped expression.
429 |
430 |
431 |
432 |
433 | Evaluate this untyped expression with the given variable environment.
434 |
435 |
436 |
437 |
438 | Evaluate this typed expression with the given variable environment.
439 |
440 |
441 |
442 |
443 | Evaluate this typed expression.
444 |
445 |
446 |
447 |
448 |
449 |
450 |
451 | Extensions methods on Expr and Expr<'a> for decompiling, evaluating, and incrementally reducing quotation expressions. Also includes a bonus
452 | extension method on Type for getting the short, F#-style name of a type.
453 |
454 |
455 |
456 |
457 | Match Call(None, ...) patterns for NumericLiterals, returning the literal value as a string and suffix on success
458 |
459 |
460 |
461 |
462 | Match a sequence, list, or array op_RangeStep expression, return (startToken, endToken, startExpression, stepExpression, endExpression). Must come before Call patterns.
463 |
464 |
465 |
466 |
467 | Match a sequence, list, or array op_Range expression, return (startToken, endToken, startExpression, endExpression). Must come before Call patterns.
468 |
469 |
470 |
471 |
472 |
473 |
474 |
475 | Partial application and zero application of Lambda call (e.g. List.map (+), or id).
476 | Must come before Let and Lambdas patterns.
477 | Cases: 1) Let .. Lambdas .. Call
478 | 2) Lambdas .. Call
479 |
480 |
481 |
482 |
483 | Test whether the given expression represents a tuple let binding: e.g. let x,y = 1,2.
484 | Must come before Let pattern and after IncompleteLambdaCall pattern.
485 |
486 |
487 |
488 |
489 | Test whether the Expr is a Var and equals the given Var property-wise
490 |
491 |
492 |
493 |
494 |
495 |
496 |
497 | Match non-custom binary infix Call patterns.
498 | Must come before Call pattern.
499 |
500 |
501 |
502 |
503 | Matches lambda values, returning the demanged (but not source) name of the lambda
504 |
505 |
506 |
507 |
508 |
509 |
510 |
511 | Extra Quoation patterns for sprinting and reducing Quotation Expressions
512 |
513 |
514 |
515 |
516 |
517 |
518 |
519 |
520 |
521 |
522 |
523 |
524 |
525 |
526 |
527 |
528 |
529 |
530 |
531 | sprints the generic arguments of a call if definitely not inferable.
532 |
533 |
534 |
535 |
536 |
537 |
538 |
539 | Determine whether the generic args for a call are inferable
540 |
541 |
542 |
543 |
544 | Sprint the F#-style type signature of the given Type. Handles known type abbreviations,
545 | simple types, arbitrarily complex generic types (multiple parameters and nesting),
546 | lambdas, tuples, and arrays.
547 |
548 |
549 |
550 |
551 |
552 |
553 |
554 | get the source name for the Module or F# Function represented by the given MemberInfo
555 |
556 |
557 |
558 |
559 |
560 |
561 |
562 |
563 |
564 |
565 | is the top-level FSI module
566 |
567 |
568 |
569 |
570 |
571 |
572 |
573 |
574 |
575 |
576 |
577 |
578 |
579 |
580 |
581 |
582 |
583 |
584 |
585 | try to find the first class symbolic function representation of a "op_" function name
586 |
587 |
588 |
589 |
590 |
591 |
592 |
593 |
594 |
595 |
596 |
597 |
598 |
599 |
600 |
601 |
602 |
603 |
604 |
605 | Extra reflection functions sprinting and reducing Quotation Expressions
606 |
607 |
608 |
609 |
610 |
611 |
612 |
613 |
614 |
615 |
616 |
617 |
618 |
619 | Precedence
620 |
621 |
622 |
623 |
624 | Associativity
625 |
626 |
627 |
628 |
629 |
630 |
631 |
632 | Represents an operator's precedence. The lower the precedence value, the lower the binding.
633 |
634 |
635 |
636 |
637 |
638 |
639 |
640 |
641 |
642 |
643 |
644 |
645 |
646 |
647 |
648 |
649 |
650 |
651 |
652 |
653 |
654 |
655 |
656 |
657 |
658 |
659 |
660 |
661 |
662 |
663 |
664 |
665 |
666 |
667 |
668 |
669 |
670 |
671 |
672 |
673 |
674 |
675 |
676 |
677 |
678 |
679 |
680 |
681 |
682 |
683 |
684 |
685 |
686 |
687 |
688 |
689 |
690 |
691 |
692 |
693 |
694 |
695 |
696 |
697 |
698 |
699 |
700 |
701 |
702 |
703 |
704 |
705 |
706 |
707 |
708 |
709 |
710 |
711 |
712 |
713 |
714 |
715 |
716 |
717 |
718 |
719 |
720 |
721 |
722 |
723 |
724 |
725 |
726 |
727 |
728 |
729 |
730 |
731 |
732 |
733 |
734 |
735 |
736 |
737 |
738 |
739 |
740 |
741 |
742 |
743 |
744 |
745 |
746 |
747 |
748 |
749 |
750 |
751 |
752 |
753 |
754 |
755 |
756 |
757 |
758 |
759 |
760 |
761 |
762 |
763 |
764 |
765 |
766 |
767 |
768 |
769 |
770 |
771 |
772 |
773 |
774 |
775 |
776 |
777 |
778 |
779 |
780 |
781 |
782 |
783 |
784 |
785 |
786 |
787 |
788 |
789 |
790 |
791 |
792 |
793 |
794 |
795 |
796 |
797 |
798 |
799 | Print the newline concated source code reduce steps of the given expression to stdout.
800 |
801 |
802 |
803 |
804 | Determine whether the given expression is reduced.
805 |
806 |
807 |
808 |
809 | Convert the given expression with the given variable environment to a list of all of its Reduce steps in order.
810 |
811 |
812 |
813 |
814 | Reduce the given expression by one step with the given variable environment: convert each branch of the given expression to a Value expression of its
815 | evaluation if each sub-branch of the branch is reduced.
816 | If this expression is already reduced, or cannot be reduced, returns itself.
817 |
818 |
819 |
820 |
821 | Evaluate the given typed expression with the given variable environment.
822 |
823 |
824 |
825 |
826 | Evaluate the given untyped expression with the given variable environment.
827 |
828 |
829 |
830 |
831 | Convert the given expression to a list of all of its Reduce steps in order.
832 |
833 |
834 |
835 |
836 | Reduce by one step: convert each branch of the given expression to a Value expression of its
837 | evaluation if each sub-branch of the branch is reduced.
838 | If this expression is already reduced, or cannot be reduced, returns itself.
839 |
840 |
841 |
842 |
843 | Decompile given expression to its source code representation. Sub-expressions which are
844 | not currently supported will fallback on the default Expr.ToString() implementation.
845 |
846 |
847 |
848 |
849 | Evaluate the given typed expression.
850 |
851 |
852 |
853 |
854 | Evaluate the given untyped expression.
855 |
856 |
857 |
858 |
859 | Operators on Expr and Expr<'a> for decompiling, evaluating, and incrementally reducing quotation expressions.
860 |
861 |
862 |
863 |
864 |
865 |
866 |
867 |
868 |
869 |
870 |
871 |
872 |
873 |
874 |
875 |
876 |
877 |
878 |
879 | Construct a Value from an evaluated expression
880 |
881 |
882 |
883 |
884 |
885 |
886 |
887 |
888 |
889 |
890 |
891 |
892 |
893 |
--------------------------------------------------------------------------------
/packages/Unquote.2.2.2/lib/net40/Unquote.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Unquote
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | Exception used to signal assertion failure to be caught by any exception framework
20 | (used when not NUnit or xUnit.net or when compiled for Silverlight)
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 | Exception used to distinguish an error in the quotation evaluation engine.
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 | Test wether the given expr fails with the given expected exception (or a subclass thereof) when the additional assertion on the exception object holds.
61 |
62 |
63 |
64 |
65 | Test wether the given expr fails with the given expected exception (or a subclass thereof).
66 |
67 |
68 |
69 |
70 | Evaluate the given boolean expression: if false output incremental eval steps using
71 | 1) stdout if fsi mode
72 | 2) framework fail methods if Xunit or Nunit present
73 | 3) System.Exception if release mode.
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 | Functions and values public inline Operator functions rely on (and therefore must be public,
103 | even though we do not want to expose them publically).
104 |
105 |
106 |
107 |
108 | Operators on Expr and Expr<'a> for performing unit test assertions.
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 | aty is the arg type, bty is the return type, x is the arg
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 | name is the name of the unary op method, aty is the arg type, x is the arg
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 | Binary ops of the form 'a->int->'a
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 | name is the name of the method, aty is the type of the first arg, bty is the type of the second arg,
264 | x is the first arg, y is the second arg.
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 | The purpose of these operator implementations is two fold 1) many F# operators do not include dynamic impls,
327 | so we must give them. 2) even those operators which are given dynamic impls do not perform well since they
328 | need to be accessed via reflection, so we give "native" impls here.
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 |
380 |
381 | "reraise" the given exception, preserving the stacktrace (e.g. for InnerExceptions of TargetInvocation exceptions)
382 |
383 |
384 |
385 |
386 | Strip possibly nested target invocation exception
387 |
388 |
389 |
390 |
391 |
392 |
393 |
394 | The F#-style signature. Note: this property is out-of-place in this assembly and may be moved elsewhere in future versions.
395 |
396 |
397 |
398 |
399 | Determine whether this expression is reduced.
400 |
401 |
402 |
403 |
404 | Convert the given expression to a list of all of its Reduce steps in order.
405 |
406 |
407 |
408 |
409 | Convert this expression with the given variable environment to a list of all of its Reduce steps in order.
410 |
411 |
412 |
413 |
414 | Reduce this expression by one step: convert each branch of the given expression to a Value expression of its
415 | evaluation if each sub-branch of the branch is reduced.
416 | If this expression is already reduced, or cannot be reduced, returns itself.
417 |
418 |
419 |
420 |
421 | Reduce this expression by one step with the given variable environment: convert each branch of the given expression to a Value expression of its
422 | evaluation if each sub-branch of the branch is reduced.
423 | If this expression is already reduced, or cannot be reduced, returns itself.
424 |
425 |
426 |
427 |
428 | Decompile this expression to its source code representation. Sub-expressions which are
429 | not currently supported will fallback on the default Expr.ToString() implementation.
430 |
431 |
432 |
433 |
434 | Evaluate this untyped expression.
435 |
436 |
437 |
438 |
439 | Evaluate this untyped expression with the given variable environment.
440 |
441 |
442 |
443 |
444 | Evaluate this typed expression with the given variable environment.
445 |
446 |
447 |
448 |
449 | Evaluate this typed expression.
450 |
451 |
452 |
453 |
454 |
455 |
456 |
457 | Extensions methods on Expr and Expr<'a> for decompiling, evaluating, and incrementally reducing quotation expressions. Also includes a bonus
458 | extension method on Type for getting the short, F#-style name of a type.
459 |
460 |
461 |
462 |
463 | Match Call(None, ...) patterns for NumericLiterals, returning the literal value as a string and suffix on success
464 |
465 |
466 |
467 |
468 | Match a sequence, list, or array op_RangeStep expression, return (startToken, endToken, startExpression, stepExpression, endExpression). Must come before Call patterns.
469 |
470 |
471 |
472 |
473 | Match a sequence, list, or array op_Range expression, return (startToken, endToken, startExpression, endExpression). Must come before Call patterns.
474 |
475 |
476 |
477 |
478 |
479 |
480 |
481 | Partial application and zero application of Lambda call (e.g. List.map (+), or id).
482 | Must come before Let and Lambdas patterns.
483 | Cases: 1) Let .. Lambdas .. Call
484 | 2) Lambdas .. Call
485 |
486 |
487 |
488 |
489 | Test whether the given expression represents a tuple let binding: e.g. let x,y = 1,2.
490 | Must come before Let pattern and after IncompleteLambdaCall pattern.
491 |
492 |
493 |
494 |
495 | Test whether the Expr is a Var and equals the given Var property-wise
496 |
497 |
498 |
499 |
500 |
501 |
502 |
503 | Match non-custom binary infix Call patterns.
504 | Must come before Call pattern.
505 |
506 |
507 |
508 |
509 | Matches lambda values, returning the demanged (but not source) name of the lambda
510 |
511 |
512 |
513 |
514 |
515 |
516 |
517 | Extra Quoation patterns for sprinting and reducing Quotation Expressions
518 |
519 |
520 |
521 |
522 |
523 |
524 |
525 |
526 |
527 |
528 |
529 |
530 |
531 |
532 |
533 |
534 |
535 |
536 |
537 | sprints the generic arguments of a call if definitely not inferable.
538 |
539 |
540 |
541 |
542 |
543 |
544 |
545 | Determine whether the generic args for a call are inferable
546 |
547 |
548 |
549 |
550 | Sprint the F#-style type signature of the given Type. Handles known type abbreviations,
551 | simple types, arbitrarily complex generic types (multiple parameters and nesting),
552 | lambdas, tuples, and arrays.
553 |
554 |
555 |
556 |
557 |
558 |
559 |
560 | get the source name for the Module or F# Function represented by the given MemberInfo
561 |
562 |
563 |
564 |
565 |
566 |
567 |
568 |
569 |
570 |
571 | is the top-level FSI module
572 |
573 |
574 |
575 |
576 |
577 |
578 |
579 |
580 |
581 |
582 |
583 |
584 |
585 |
586 |
587 |
588 |
589 |
590 |
591 | try to find the first class symbolic function representation of a "op_" function name
592 |
593 |
594 |
595 |
596 |
597 |
598 |
599 |
600 |
601 |
602 |
603 |
604 |
605 |
606 |
607 |
608 |
609 |
610 |
611 | Extra reflection functions sprinting and reducing Quotation Expressions
612 |
613 |
614 |
615 |
616 |
617 |
618 |
619 |
620 |
621 |
622 |
623 |
624 |
625 | Precedence
626 |
627 |
628 |
629 |
630 | Associativity
631 |
632 |
633 |
634 |
635 |
636 |
637 |
638 | Represents an operator's precedence. The lower the precedence value, the lower the binding.
639 |
640 |
641 |
642 |
643 |
644 |
645 |
646 |
647 |
648 |
649 |
650 |
651 |
652 |
653 |
654 |
655 |
656 |
657 |
658 |
659 |
660 |
661 |
662 |
663 |
664 |
665 |
666 |
667 |
668 |
669 |
670 |
671 |
672 |
673 |
674 |
675 |
676 |
677 |
678 |
679 |
680 |
681 |
682 |
683 |
684 |
685 |
686 |
687 |
688 |
689 |
690 |
691 |
692 |
693 |
694 |
695 |
696 |
697 |
698 |
699 |
700 |
701 |
702 |
703 |
704 |
705 |
706 |
707 |
708 |
709 |
710 |
711 |
712 |
713 |
714 |
715 |
716 |
717 |
718 |
719 |
720 |
721 |
722 |
723 |
724 |
725 |
726 |
727 |
728 |
729 |
730 |
731 |
732 |
733 |
734 |
735 |
736 |
737 |
738 |
739 |
740 |
741 |
742 |
743 |
744 |
745 |
746 |
747 |
748 |
749 |
750 |
751 |
752 |
753 |
754 |
755 |
756 |
757 |
758 |
759 |
760 |
761 |
762 |
763 |
764 |
765 |
766 |
767 |
768 |
769 |
770 |
771 |
772 |
773 |
774 |
775 |
776 |
777 |
778 |
779 |
780 |
781 |
782 |
783 |
784 |
785 |
786 |
787 |
788 |
789 |
790 |
791 |
792 |
793 |
794 |
795 |
796 |
797 |
798 |
799 |
800 |
801 |
802 |
803 |
804 |
805 | Print the newline concated source code reduce steps of the given expression to stdout.
806 |
807 |
808 |
809 |
810 | Determine whether the given expression is reduced.
811 |
812 |
813 |
814 |
815 | Convert the given expression with the given variable environment to a list of all of its Reduce steps in order.
816 |
817 |
818 |
819 |
820 | Reduce the given expression by one step with the given variable environment: convert each branch of the given expression to a Value expression of its
821 | evaluation if each sub-branch of the branch is reduced.
822 | If this expression is already reduced, or cannot be reduced, returns itself.
823 |
824 |
825 |
826 |
827 | Evaluate the given typed expression with the given variable environment.
828 |
829 |
830 |
831 |
832 | Evaluate the given untyped expression with the given variable environment.
833 |
834 |
835 |
836 |
837 | Convert the given expression to a list of all of its Reduce steps in order.
838 |
839 |
840 |
841 |
842 | Reduce by one step: convert each branch of the given expression to a Value expression of its
843 | evaluation if each sub-branch of the branch is reduced.
844 | If this expression is already reduced, or cannot be reduced, returns itself.
845 |
846 |
847 |
848 |
849 | Decompile given expression to its source code representation. Sub-expressions which are
850 | not currently supported will fallback on the default Expr.ToString() implementation.
851 |
852 |
853 |
854 |
855 | Evaluate the given typed expression.
856 |
857 |
858 |
859 |
860 | Evaluate the given untyped expression.
861 |
862 |
863 |
864 |
865 | Operators on Expr and Expr<'a> for decompiling, evaluating, and incrementally reducing quotation expressions.
866 |
867 |
868 |
869 |
870 |
871 |
872 |
873 |
874 |
875 |
876 |
877 |
878 |
879 |
880 |
881 |
882 |
883 |
884 |
885 | Construct a Value from an evaluated expression
886 |
887 |
888 |
889 |
890 |
891 |
892 |
893 |
894 |
895 |
896 |
897 |
898 |
899 |
--------------------------------------------------------------------------------