Adventures in F# - Part 5
It’s about time for me to develop some application to put the basics in use. I will develop it in Visual Studio so first is to get accustomed to using F# in VS 2013. There are 5 project types for F#:
- Console Application
- Library
- Tutorial
- Portable Library
- Portable Library (Legacy)
Portable Library should be helpful when developing universal Windows Store apps. For my purposes Console Application and Library should be enough. Before going any further I decided to check out the Tutorial project. So below are today’s notes on using F# in VS 2013 and from the tutorial project
Notes
- Tutorial project comes with a single Tutorial.fsx file with all the sample code. Console Application, on the other hand, comes with Program.fs. Apparently an fsx is the extension for F# script files: “An F# script file is a normal F# source code file, except that .fsx files have a few extra capabilities.”.
- Ctrl + Alt + F combination opens the F# Interactive Window
- You can select a code block and run it in the interactive window by right-clikcing and selecting “Execute in Interactive” or using Alt + Enter shortcut.
- A module is a logical grouping of related code segments. The code in a module must be indented. When types and functions are inside modules they can be accessed by their fully-qualified names from outside the module:
module MyModule1 =
let module1Value = 100
let module1Function x =
x + 10
module MyModule2 =
let module2Value = 121
let module2Function x =
x * (MyModule1.module1Function module2Value)
MyModule2.module2Function 5
- Modules can have public, private or internal access modifiers. The default is public.
- A foreach loop can be defined as for i in {values} -> … For example
let sampleTableOfSquares = [ for i in 0 .. 99 -> (i, i*i) ]
- When defining functions parenthesis can be used optionally. I think this makes the function look more “mathy” and a littler easier to read.
let func1a (x) = x*x + 3
- To improve the readability further it sounds like a good idea to annotate the type always (even when it can be inferred automatically)
let func2 (x:int) = 2*x*x - x/5 + 3
- Boolean operations are straightforward
let boolean1 = true
let boolean2 = false
let boolean3 = not boolean1 && (boolean2 || false)
printfn "The expression 'not boolean1 && (boolean2 || false)' is %A" boolean3
- Double-quotes can be used inside strings be enclosing them with triple quotes
let string4 = """He said "hello world" after you did"""
- A fragment of a string can be accessed by this notation:
let string1 = "Hello"
let string2 = "world"
let helloWorld = string1 + " " + string2
let substring = helloWorld.[0..6]
- A tuples is a set of ordered values
let tuple1 = (1, "fred", 3.1415)
- Lists can be defined in various syntax
let list1 = [ ]
let list2 = [ 1; 2; 3 ]
let list3 = 42 :: list2
let numberList = [ 1 .. 1000 ]
let squares =
numberList
|> List.map (fun x -> x*x)
- Classes can be defined by type keyword
type Vector2D(dx : float, dy : float) =
let length = sqrt (dx*dx + dy*dy)
member this.DX = dx
member this.DY = dy
member this.Length = length
member this.Scale(k) = Vector2D(k * this.DX, k * this.DY)
- Generics classes are supported
type StateTracker<'T>(initialElement: 'T) =
let mutable states = [ initialElement ]
- Classes can implement interfaces
type ReadFile() =
let file = new System.IO.StreamReader("readme.txt")
member this.ReadLine() = file.ReadLine()
interface System.IDisposable with
member this.Dispose() = file.Close()
-
Arrays use a similar syntax to lists except [ … ] operators are used
let array1 = [| 1 .. 1000 |]
let evenNumbers = Array.init 1001 (fun n -> n * 2)
- Sequences are evaluated on-demand and are re-evaluated each time they are iterated. They are defined by curly braces
let numbersSeq = seq { 1 .. 1000 }
- Recursive functions are defined by let rec keyword
let rec factorial n =
if n = 0 then 1 else n * factorial (n-1)
- Record types can be created by type keyword and curly braces
type ContactCard =
{ Name : string;
Phone : string;
Verified : bool }
- Union types can be created by type keyword and pipe-separated values
type Suit =
| Hearts
| Clubs
| Diamonds
| Spades
- Option values are any kind of value tagged with either ‘Some’ or ‘None’.
- Code can be annotated with units of measure when using F# arithmetic over numeric types
open Microsoft.FSharp.Data.UnitSystems.SI.UnitNames
[<Measure>]
type mile =
/// Conversion factor mile to meter: meter is defined in SI.UnitNames
static member asMeter = 1600.<meter/mile>
- Large arrays can be processed in parallel
let oneBigArray = [| 0 .. 100000 |]
// do some CPU intensive computation
let rec computeSomeFunction x =
if x <= 2 then 1
else computeSomeFunction (x - 1) + computeSomeFunction (x - 2)
// Do a parallel map over a large input array
let computeResults() = oneBigArray |> Array.Parallel.map (fun x -> computeSomeFunction (x % 20))
printfn "Parallel computation results: %A" (computeResults())
- Events are also supported
open System
// create instance of Event object that consists of subscription point (event.Publish) and event trigger (event.Trigger)
let simpleEvent = new Event<int>()
// add handler
simpleEvent.Publish.Add(
fun x -> printfn "this is handler was added with Publish.Add: %d" x)
// trigger event
simpleEvent.Trigger(5)
Conclusion
I like the tutorial script that came with VS. It shows all basic aspects in one place. I think I’ve spent enough time covering the basics. I need to dive deeper and develop something on my own or at least check out complete applications which I’m going to do next.