SlideShare a Scribd company logo
@kitlovesfsharp www.github.com/misterspeedy
F# For an Easy Life!
Kit Eason
F# in a nutshell
 Microsoft first class supported language for .NET
 Supports OO and functional paradigms
 Compiles to CLI like C#, VB.Net
 First class citizen in VS2010 and VS2012 (free!). (Also in 2013 preview)
 Open source, runs on Mono (use Xamarin)
 Strongly typed
F# functions
 Use ‘let’ to declare functions and values
let add x y =
x + y
 The return value of the function is the last value calculated (no ‘return’
statement
let add x y =
x + y
 Types are inferred (at design time)
 Argument lists don’t have brackets
F# Interactive (FSI)
> let add x y =
x + y;;
val add : x:int -> y:int -> int
> add 3 4;;
val it : int = 7
>
• Use F# interactive to define and try out functions
Calculating present value
> let presentValue fv r t =
fv * (1.+r) ** (-t);;
val presentValue : fv:float -> r:float -> t:float -> float
> presentValue 2000.0 0.07 10.;;
val it : float = 1016.698584
>
• Formulae can be represented very directly
The ‘map’ function
 Take some collection (array, list, IEnumerable)
 For every value calculate and return some other value
 Result is another array/list/IEnumerable containing the results
let someSquares min max =
// This generates an array from min to max:
let numbers = [|min..max|]
Array.map (fun x -> x * x) numbers
val someSquares : min:int -> max:int -> int []
> someSquares 100 110;;
val it : int [] =
[|10000; 10201; 10404; 10609; 10816; 11025; 11236; 11449; 11664;
11881;
12100|]
>
The forward pipe operator |>
 Takes the output from the preceding function
 Places it into the (last) parameter of the following function
let add x y =
x + y
let multiply x y =
x * y
val add : x:int -> y:int -> int
val multiply : x:int -> y:int -> int
> add 2 3 |> multiply 5;;
val it : int = 25
>
The forward pipe operator |> (2)
 Comes into its own when dealing with collections
let rootMeanSquare min max =
[|min..max|]
|> Array.map (fun x -> x * x)
|> Array.average
|> sqrt
val rootMeanSquare : min:float -> max:float -> float
> rootMeanSquare -10.0 10.0;;
val it : float = 6.055300708
>
The ‘mapi’ function
 Like ‘map’ but provides you with an index value 0, 1, 2 etc.
let someAdditions min max =
[|min..max|]
|> Array.mapi (fun i x -> i + x)
val someAdditions : min:int -> max:int -> int []
> someAdditions 100 110;;
val it : int [] = [|100; 102; 104; 106; 108; 110; 112;
114; 116; 118; 120|]
>
Calculating present value of a cashflow
 Calculate the present value of a cashflow starting at time 0
let presentValue fv r t =
fv * (1.+r) ** (-t)
let cfPresentValue cf r =
cf
|> Array.mapi (fun t amt -> presentValue amt r (float(t)))
|> Array.sum
val presentValue : fv:float -> r:float -> t:float -> float
val cfPresentValue : cf:float [] -> r:float -> float
> cfPresentValue [|1000.0; 2000.0; 2500.0|] 0.07;;
val it : float = 5052.755699
>
Great Circle Distance
Unit Testing and TDD
 Create a new F# library project
 Use Nuget to bring in FSUnit
 Add GreatCircleTests.fs
module GreatCircleTests
open NUnit.Framework
open FsUnit
Write a trivial test!
module GreatCircleTests
open NUnit.Framework
open FsUnit
[<TestFixture>]
type ``Given the GreatCircleDistance function``() =
[<Test>]
member x.``The function returns 0 for a journey between the same
points``() =
let expected = 0.
let actual = GreatCircle.Distance 45. 50. 45. 50.
actual |> should equal expected
Pass the test!
module GreatCircle
let Distance lat1 long1 lat2 long2 =
0.
What’s the next simplest test?
[<Test>]
member x.``The function returns 20014 km for a journey between the poles``() =
let expected = 20014.
let actual = GreatCircle.Distance -90. 0. 90. 0.
actual |> should equal expected
We’re gonna need an algorithm!
var R = 6371; // km
var dLat = (lat2-lat1).toRad();
var dLon = (lon2-lon1).toRad();
var lat1 = lat1.toRad();
var lat2 = lat2.toRad();
var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
var d = R * c;
How’s this?
open System
let Distance lat1 lon1 lat2 lon2 =
let EarthRadius = 6378.1
let Deg2Rad deg =
deg * Math.PI / 180.
let lat1r = lat1 |> Deg2Rad
let lat2r = lat2 |> Deg2Rad
let dLat = lat2 - lat1 |> Deg2Rad
let dLon = lon2 - lon1 |> Deg2Rad
let a = (sin(dLat/2.) ** 2.) +
(sin(dLon/2.) ** 2.) * cos(lat1r) * cos(lat2r)
let c = 2. * atan2 (sqrt(a)) (sqrt(1.-a))
c * EarthRadius
Whuuuuuuuuuuuuuuuuuu?
------ Test started: Assembly: FSUnitTestingExample.dll ------
Test 'GreatCircleTests+Given the GreatCircleDistance function.The
function returns 20014 km for a journey between the poles' failed:
Expected: 20014.0d
But was: 20037.392103861061d
at FsUnit.TopLevelOperators.should[a,a](FSharpFunc`2 f, a x,
Object y)
C:CodeVS2012FSUnitTestingExampleFSUnitTestingExampleGre
atCircleTests.fs(28,0): at GreatCircleTests.Given the
GreatCircleDistance function.The function returns 20014 km for a
journey between the poles()
1 passed, 1 failed, 0 skipped, took 0.37 seconds (NUnit 2.6.1).
They all laughed at Christopher Columbus…
[<TestFixture>]
type ``Given the GreatCircleDistance function``() =
let margin = 0.003
[<Test>]
member x.``The function returns 0 for a journey between the same points``() =
let expected = 0.
let actual = GreatCircle.Distance 45. 50. 45. 50.
actual |> should (equalWithin margin) expected
[<Test>]
member x.``The function returns 20014 km for a journey between the poles``() =
let expected = 20014.
let actual = GreatCircle.Distance -90. 0. 90. 0.
let error = expected * margin
actual |> should (equalWithin error) expected
Further tests better added as cases
// Travel no distance:
[<TestCase(0., 0., 0., 0., 0.)>]
// Travel along the equator eastwards for 90 degrees:
[<TestCase(0., 0., 0., 90., 10018.79)>]
// Travel along the equator westwards for 90 degrees:
[<TestCase(0., 0., 0., -90., 10018.79)>]
// Travel along the equator eastwards for 180 degrees:
[<TestCase(0., 0., 0., 180., 20037.58)>]
// Travel along the equator westwards for 180 degrees:
[<TestCase(0., 0., 0., -180., 20037.58)>]
// Travel along the meridian northwards 90 degrees:
[<TestCase(0., 0., 90., 0., 10018.79)>]
// Travel along the meridian soutwards 90 degrees:
[<TestCase(0., 0., -90., 0., 10018.79)>]
// Travel from Farnham to Reigate:
[<TestCase(51.214, -0.799, 51.230, -0.188, 42.6)>]
// Travel from London to Sidney Australia:
[<TestCase(51.51, -0.13, -33.86, 151.21, 16998.)>]
member t.``the function returns the right result``(lat1, long1, lat2, long2, expected) =
let actual = GreatCircle.Distance lat1 long1 lat2 long2
let error = expected * margin
actual |> should (equalWithin error) expected
Information-Rich Programming
 Bring large, structured data sources into the code in a type-safe way…
with Intellisense!
 Implemented by ‘Type Providers’
 Introduced with F#3.0 (VS2012)
 Code-gen free!
Information Rich Programming
22
Freebase
Nuget and Fsharp.Data
Get airports and locations
/// Gets airports between a specified start and end index (to facilitate paged access).
let GetAirportsPaged startIndex pageSize =
query {
for airport in dc.Transportation.Aviation.Airports do
where ( airport.Geolocation <> null
&& airport.Geolocation.Latitude.HasValue
&& airport.Geolocation.Longitude.HasValue
)
skip startIndex
take pageSize
select (airport.Name,
airport.Geolocation.Latitude.Value,
airport.Geolocation.Longitude.Value)
}
|> Array.ofSeq
|> Array.map (fun (name, lat, long) -> { Name = name; Lat = lat; Long = long })
Get airports and locations (2)
/// Gets all airports from Freebase which have a defined location.
let GetAllAirports pageSize =
let rec getPage startIndex acc =
let page = GetAirportsPaged startIndex pageSize
if page.Length > 0 then
Array.append acc (getPage (startIndex+pageSize) page)
else
acc
getPage 0 [||]
Get closest airports
/// Gets the closest n airports to the given airport.
let GetClosest target count airportList =
airportList
|> Array.map (fun airport -> airport, (DistanceBetween
(airport.Lat) (airport.Long) (target.Lat) (target.Long)))
|> Array.sortBy (fun (airport, distance) -> distance)
|> Seq.truncate count
|> Array.ofSeq
Get closest airports to a named airport
/// Gets airports near an airport specified by name.
let GetAirportsNear name airportList =
let target = airportList
|> Array.tryFind (fun airport -> airport.Name.Contains(name))
if target.IsSome then
airportList
|> GetClosest target.Value 20
|> Array.iter (fun (airport, distance) -> printfn "%s - %f km" airport.Name distance)
else
printfn "Could not find %s" name

More Related Content

PPTX
Столпы функционального программирования для адептов ООП, Николай Мозговой
PPTX
Image Recognition with Neural Network
PPT
Vector3
PDF
Csharp_Chap13
PDF
Kotlin Perfomance on Android / Александр Смирнов (Splyt)
PDF
Orthogonal Functional Architecture
PDF
All Aboard The Scala-to-PureScript Express!
PDF
Hw09 Hadoop + Clojure
Столпы функционального программирования для адептов ООП, Николай Мозговой
Image Recognition with Neural Network
Vector3
Csharp_Chap13
Kotlin Perfomance on Android / Александр Смирнов (Splyt)
Orthogonal Functional Architecture
All Aboard The Scala-to-PureScript Express!
Hw09 Hadoop + Clojure

What's hot (20)

PDF
Introduction to functional programming using Ocaml
PDF
Learn a language : LISP
DOCX
.net progrmming part2
PPTX
Java Foundations: Lists, ArrayList<T>
PPTX
Java simple programs
DOCX
Collection frame work
PPTX
Lecture 5, c++(complete reference,herbet sheidt)chapter-15
PPTX
Vector class in C++
PDF
Laziness, trampolines, monoids and other functional amenities: this is not yo...
PDF
The Ring programming language version 1.3 book - Part 25 of 88
PDF
MTL Versus Free
PDF
Atomically { Delete Your Actors }
PDF
If You Think You Can Stay Away from Functional Programming, You Are Wrong
PPTX
Chapter i(introduction to java)
PDF
Java 8 Stream API. A different way to process collections.
PPTX
Scala - where objects and functions meet
TXT
Operator overloading (binary)
PPTX
Java Foundations: Maps, Lambda and Stream API
DOCX
Arrry structure Stacks in data structure
PDF
deep learning library coyoteの開発(CNN編)
Introduction to functional programming using Ocaml
Learn a language : LISP
.net progrmming part2
Java Foundations: Lists, ArrayList<T>
Java simple programs
Collection frame work
Lecture 5, c++(complete reference,herbet sheidt)chapter-15
Vector class in C++
Laziness, trampolines, monoids and other functional amenities: this is not yo...
The Ring programming language version 1.3 book - Part 25 of 88
MTL Versus Free
Atomically { Delete Your Actors }
If You Think You Can Stay Away from Functional Programming, You Are Wrong
Chapter i(introduction to java)
Java 8 Stream API. A different way to process collections.
Scala - where objects and functions meet
Operator overloading (binary)
Java Foundations: Maps, Lambda and Stream API
Arrry structure Stacks in data structure
deep learning library coyoteの開発(CNN編)
Ad

Similar to F# Presentation for SmartDevs, Hereford (20)

PDF
Monads in Swift
PDF
How to become an Android dev starting from iOS (and vice versa)
PDF
22 scheme OOPs with C++ BCS306B_module3.pdf
PPT
Lecture#6 functions in c++
PPTX
Go Programming Language (Golang)
PPTX
How to add an optimization for C# to RyuJIT
PDF
FS2 for Fun and Profit
PDF
TI1220 Lecture 6: First-class Functions
PDF
От Java Threads к лямбдам, Андрей Родионов
PDF
From Java to Scala - advantages and possible risks
ODP
From object oriented to functional domain modeling
PPTX
Using-Python-Libraries.9485146.powerpoint.pptx
PDF
From object oriented to functional domain modeling
PDF
Java/Scala Lab: Анатолий Кметюк - Scala SubScript: Алгебра для реактивного пр...
PPTX
operator overloading
PPTX
functions
PDF
Programming Sideways: Asynchronous Techniques for Android
PDF
Threads, Queues, and More: Async Programming in iOS
PDF
Monadologie
PDF
Hadoop + Clojure
Monads in Swift
How to become an Android dev starting from iOS (and vice versa)
22 scheme OOPs with C++ BCS306B_module3.pdf
Lecture#6 functions in c++
Go Programming Language (Golang)
How to add an optimization for C# to RyuJIT
FS2 for Fun and Profit
TI1220 Lecture 6: First-class Functions
От Java Threads к лямбдам, Андрей Родионов
From Java to Scala - advantages and possible risks
From object oriented to functional domain modeling
Using-Python-Libraries.9485146.powerpoint.pptx
From object oriented to functional domain modeling
Java/Scala Lab: Анатолий Кметюк - Scala SubScript: Алгебра для реактивного пр...
operator overloading
functions
Programming Sideways: Asynchronous Techniques for Android
Threads, Queues, and More: Async Programming in iOS
Monadologie
Hadoop + Clojure
Ad

Recently uploaded (20)

PDF
A novel scalable deep ensemble learning framework for big data classification...
PPTX
A Presentation on Artificial Intelligence
PDF
A comparative study of natural language inference in Swahili using monolingua...
PPTX
OMC Textile Division Presentation 2021.pptx
PDF
Assigned Numbers - 2025 - Bluetooth® Document
PDF
1 - Historical Antecedents, Social Consideration.pdf
PDF
ENT215_Completing-a-large-scale-migration-and-modernization-with-AWS.pdf
PDF
Microsoft Solutions Partner Drive Digital Transformation with D365.pdf
PDF
WOOl fibre morphology and structure.pdf for textiles
PDF
Enhancing emotion recognition model for a student engagement use case through...
PDF
Heart disease approach using modified random forest and particle swarm optimi...
PDF
Hybrid model detection and classification of lung cancer
PDF
Univ-Connecticut-ChatGPT-Presentaion.pdf
PPTX
Digital-Transformation-Roadmap-for-Companies.pptx
PDF
Agricultural_Statistics_at_a_Glance_2022_0.pdf
PPTX
A Presentation on Touch Screen Technology
PDF
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
PPTX
SOPHOS-XG Firewall Administrator PPT.pptx
PDF
gpt5_lecture_notes_comprehensive_20250812015547.pdf
PDF
Mushroom cultivation and it's methods.pdf
A novel scalable deep ensemble learning framework for big data classification...
A Presentation on Artificial Intelligence
A comparative study of natural language inference in Swahili using monolingua...
OMC Textile Division Presentation 2021.pptx
Assigned Numbers - 2025 - Bluetooth® Document
1 - Historical Antecedents, Social Consideration.pdf
ENT215_Completing-a-large-scale-migration-and-modernization-with-AWS.pdf
Microsoft Solutions Partner Drive Digital Transformation with D365.pdf
WOOl fibre morphology and structure.pdf for textiles
Enhancing emotion recognition model for a student engagement use case through...
Heart disease approach using modified random forest and particle swarm optimi...
Hybrid model detection and classification of lung cancer
Univ-Connecticut-ChatGPT-Presentaion.pdf
Digital-Transformation-Roadmap-for-Companies.pptx
Agricultural_Statistics_at_a_Glance_2022_0.pdf
A Presentation on Touch Screen Technology
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
SOPHOS-XG Firewall Administrator PPT.pptx
gpt5_lecture_notes_comprehensive_20250812015547.pdf
Mushroom cultivation and it's methods.pdf

F# Presentation for SmartDevs, Hereford

  • 2. F# in a nutshell  Microsoft first class supported language for .NET  Supports OO and functional paradigms  Compiles to CLI like C#, VB.Net  First class citizen in VS2010 and VS2012 (free!). (Also in 2013 preview)  Open source, runs on Mono (use Xamarin)  Strongly typed
  • 3. F# functions  Use ‘let’ to declare functions and values let add x y = x + y  The return value of the function is the last value calculated (no ‘return’ statement let add x y = x + y  Types are inferred (at design time)  Argument lists don’t have brackets
  • 4. F# Interactive (FSI) > let add x y = x + y;; val add : x:int -> y:int -> int > add 3 4;; val it : int = 7 > • Use F# interactive to define and try out functions
  • 5. Calculating present value > let presentValue fv r t = fv * (1.+r) ** (-t);; val presentValue : fv:float -> r:float -> t:float -> float > presentValue 2000.0 0.07 10.;; val it : float = 1016.698584 > • Formulae can be represented very directly
  • 6. The ‘map’ function  Take some collection (array, list, IEnumerable)  For every value calculate and return some other value  Result is another array/list/IEnumerable containing the results let someSquares min max = // This generates an array from min to max: let numbers = [|min..max|] Array.map (fun x -> x * x) numbers val someSquares : min:int -> max:int -> int [] > someSquares 100 110;; val it : int [] = [|10000; 10201; 10404; 10609; 10816; 11025; 11236; 11449; 11664; 11881; 12100|] >
  • 7. The forward pipe operator |>  Takes the output from the preceding function  Places it into the (last) parameter of the following function let add x y = x + y let multiply x y = x * y val add : x:int -> y:int -> int val multiply : x:int -> y:int -> int > add 2 3 |> multiply 5;; val it : int = 25 >
  • 8. The forward pipe operator |> (2)  Comes into its own when dealing with collections let rootMeanSquare min max = [|min..max|] |> Array.map (fun x -> x * x) |> Array.average |> sqrt val rootMeanSquare : min:float -> max:float -> float > rootMeanSquare -10.0 10.0;; val it : float = 6.055300708 >
  • 9. The ‘mapi’ function  Like ‘map’ but provides you with an index value 0, 1, 2 etc. let someAdditions min max = [|min..max|] |> Array.mapi (fun i x -> i + x) val someAdditions : min:int -> max:int -> int [] > someAdditions 100 110;; val it : int [] = [|100; 102; 104; 106; 108; 110; 112; 114; 116; 118; 120|] >
  • 10. Calculating present value of a cashflow  Calculate the present value of a cashflow starting at time 0 let presentValue fv r t = fv * (1.+r) ** (-t) let cfPresentValue cf r = cf |> Array.mapi (fun t amt -> presentValue amt r (float(t))) |> Array.sum val presentValue : fv:float -> r:float -> t:float -> float val cfPresentValue : cf:float [] -> r:float -> float > cfPresentValue [|1000.0; 2000.0; 2500.0|] 0.07;; val it : float = 5052.755699 >
  • 12. Unit Testing and TDD  Create a new F# library project  Use Nuget to bring in FSUnit  Add GreatCircleTests.fs module GreatCircleTests open NUnit.Framework open FsUnit
  • 13. Write a trivial test! module GreatCircleTests open NUnit.Framework open FsUnit [<TestFixture>] type ``Given the GreatCircleDistance function``() = [<Test>] member x.``The function returns 0 for a journey between the same points``() = let expected = 0. let actual = GreatCircle.Distance 45. 50. 45. 50. actual |> should equal expected
  • 14. Pass the test! module GreatCircle let Distance lat1 long1 lat2 long2 = 0.
  • 15. What’s the next simplest test? [<Test>] member x.``The function returns 20014 km for a journey between the poles``() = let expected = 20014. let actual = GreatCircle.Distance -90. 0. 90. 0. actual |> should equal expected
  • 16. We’re gonna need an algorithm! var R = 6371; // km var dLat = (lat2-lat1).toRad(); var dLon = (lon2-lon1).toRad(); var lat1 = lat1.toRad(); var lat2 = lat2.toRad(); var a = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2); var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); var d = R * c;
  • 17. How’s this? open System let Distance lat1 lon1 lat2 lon2 = let EarthRadius = 6378.1 let Deg2Rad deg = deg * Math.PI / 180. let lat1r = lat1 |> Deg2Rad let lat2r = lat2 |> Deg2Rad let dLat = lat2 - lat1 |> Deg2Rad let dLon = lon2 - lon1 |> Deg2Rad let a = (sin(dLat/2.) ** 2.) + (sin(dLon/2.) ** 2.) * cos(lat1r) * cos(lat2r) let c = 2. * atan2 (sqrt(a)) (sqrt(1.-a)) c * EarthRadius
  • 18. Whuuuuuuuuuuuuuuuuuu? ------ Test started: Assembly: FSUnitTestingExample.dll ------ Test 'GreatCircleTests+Given the GreatCircleDistance function.The function returns 20014 km for a journey between the poles' failed: Expected: 20014.0d But was: 20037.392103861061d at FsUnit.TopLevelOperators.should[a,a](FSharpFunc`2 f, a x, Object y) C:CodeVS2012FSUnitTestingExampleFSUnitTestingExampleGre atCircleTests.fs(28,0): at GreatCircleTests.Given the GreatCircleDistance function.The function returns 20014 km for a journey between the poles() 1 passed, 1 failed, 0 skipped, took 0.37 seconds (NUnit 2.6.1).
  • 19. They all laughed at Christopher Columbus… [<TestFixture>] type ``Given the GreatCircleDistance function``() = let margin = 0.003 [<Test>] member x.``The function returns 0 for a journey between the same points``() = let expected = 0. let actual = GreatCircle.Distance 45. 50. 45. 50. actual |> should (equalWithin margin) expected [<Test>] member x.``The function returns 20014 km for a journey between the poles``() = let expected = 20014. let actual = GreatCircle.Distance -90. 0. 90. 0. let error = expected * margin actual |> should (equalWithin error) expected
  • 20. Further tests better added as cases // Travel no distance: [<TestCase(0., 0., 0., 0., 0.)>] // Travel along the equator eastwards for 90 degrees: [<TestCase(0., 0., 0., 90., 10018.79)>] // Travel along the equator westwards for 90 degrees: [<TestCase(0., 0., 0., -90., 10018.79)>] // Travel along the equator eastwards for 180 degrees: [<TestCase(0., 0., 0., 180., 20037.58)>] // Travel along the equator westwards for 180 degrees: [<TestCase(0., 0., 0., -180., 20037.58)>] // Travel along the meridian northwards 90 degrees: [<TestCase(0., 0., 90., 0., 10018.79)>] // Travel along the meridian soutwards 90 degrees: [<TestCase(0., 0., -90., 0., 10018.79)>] // Travel from Farnham to Reigate: [<TestCase(51.214, -0.799, 51.230, -0.188, 42.6)>] // Travel from London to Sidney Australia: [<TestCase(51.51, -0.13, -33.86, 151.21, 16998.)>] member t.``the function returns the right result``(lat1, long1, lat2, long2, expected) = let actual = GreatCircle.Distance lat1 long1 lat2 long2 let error = expected * margin actual |> should (equalWithin error) expected
  • 21. Information-Rich Programming  Bring large, structured data sources into the code in a type-safe way… with Intellisense!  Implemented by ‘Type Providers’  Introduced with F#3.0 (VS2012)  Code-gen free!
  • 25. Get airports and locations /// Gets airports between a specified start and end index (to facilitate paged access). let GetAirportsPaged startIndex pageSize = query { for airport in dc.Transportation.Aviation.Airports do where ( airport.Geolocation <> null && airport.Geolocation.Latitude.HasValue && airport.Geolocation.Longitude.HasValue ) skip startIndex take pageSize select (airport.Name, airport.Geolocation.Latitude.Value, airport.Geolocation.Longitude.Value) } |> Array.ofSeq |> Array.map (fun (name, lat, long) -> { Name = name; Lat = lat; Long = long })
  • 26. Get airports and locations (2) /// Gets all airports from Freebase which have a defined location. let GetAllAirports pageSize = let rec getPage startIndex acc = let page = GetAirportsPaged startIndex pageSize if page.Length > 0 then Array.append acc (getPage (startIndex+pageSize) page) else acc getPage 0 [||]
  • 27. Get closest airports /// Gets the closest n airports to the given airport. let GetClosest target count airportList = airportList |> Array.map (fun airport -> airport, (DistanceBetween (airport.Lat) (airport.Long) (target.Lat) (target.Long))) |> Array.sortBy (fun (airport, distance) -> distance) |> Seq.truncate count |> Array.ofSeq
  • 28. Get closest airports to a named airport /// Gets airports near an airport specified by name. let GetAirportsNear name airportList = let target = airportList |> Array.tryFind (fun airport -> airport.Name.Contains(name)) if target.IsSome then airportList |> GetClosest target.Value 20 |> Array.iter (fun (airport, distance) -> printfn "%s - %f km" airport.Name distance) else printfn "Could not find %s" name