├── .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 | --------------------------------------------------------------------------------