Functions - function values, curried, anonymous

Functions are defined with `let`
1: 
2: 
3: 
let inc1 x = x + 1
let inc1Result = inc1 1
printfn "inc1 1: %A" inc1Result

Arguments can have a type specified

1: 
2: 
let inc2 (a: int): int = a + 1
printfn "inc2 2: %A" (inc2 2)

Indentation indicates function body

1: 
2: 
3: 
4: 
5: 
let cylinderVol radius length =
  let pi = 3.14159
  length * pi * radius * radius

printfn "cylinderVol %A" (cylinderVol 3.0 20.0)

Code can also be executed without being named using a do binding. Code in a top-level do binding is executed when the module is initialized. In this case the do keyword is optional.

Partial Application

1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
let smallPipeVolume = cylinderVol 2.0
let bigPipeVolume = cylinderVol 3.0

let smallLongPipeVol = smallPipeVolume 5.0
let bigShortPipeVol = bigPipeVolume 2.0

printfn "smallLongPipeVol: %A" smallLongPipeVol
printfn "bigShortPipeVol: %A" bigShortPipeVol

Function Values (First class functions)

All functions in F# are known as function values.

The transform argument is a function that takes an int and returns an int.

1: 
2: 
3: 
let apply1 (transform: int -> int) y = transform y
let transformFunc x = x * 2
printfn "apply1 with transformFunc: %A" (apply1 transformFunc 3)

Lambda Expression (Anonymous functions?)

1: 
2: 
let lambdaResult = apply1(fun x -> x + 1) 100
printfn "lambdaResult: %A" lambdaResult

Function Composition and Pipelining

Composition operators take 2 functions and return a function

1: 
2: 
3: 
4: 
5: 
6: 
let addOne x = x + 1
let timesTwo x = x * 2
let compose1 = addOne >> timesTwo
let compose2 = addOne << timesTwo
printfn "compose1: %A" (compose1 100) // (100 + 1) * 2 = 202
printfn "compose2: %A" (compose2 100) // (100 * 2) + 1 = 201

Pipelining operators take a function and an argument and return a value (100 + 1) * 2 = 202

1: 
printfn "Pipeline result: %A" (100 |> addOne |> timesTwo)

External Functions

Call native functions (platform invoke).

Assuming the following C++ DLL:

1: 
2: 
3: 
4: 
5: 
# <stdio.h>
extern "C" void __declspec(dllexport) HelloWorld()
{
   printf("Hello world, invoked by F#!\n");
}
 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
open System.Runtime.InteropServices
module InteropWithNative =
  [<DllImport(@"C:\bin\nativedll", CallingConvention = CallingConvention.Cdecl)>]
  extern void HelloWorld()

  (**
No DLL so this is for reference only:
InteropWithNative.HelloWorld()


## Inline Functions

Functions that are integrated directly into the calling code.
Judicious use of inline functions can be used to optimise code.
   *)

let inline increment x = x + 1
type WrapInt32() =
  member inline this.IncrementByOne(x) = x + 1
  static member inline Increment(x) = x + 1

Recursive Functions

1: 
2: 
let rec fib n = if n < 2 then 1 else fib (n - 1) + fib (n - 2)
printfn "fib 5: %A" (fib 5)

Entry Point

The entry point of an F# application. Must be the last let binding in the project.

If no entry point is specified, the last top-level binding is used as the entry point.

NOTE: EntryPoint attributes are ignored in FSI

1: 
2: 
3: 
4: 
[<EntryPoint>]
let main args =
  printfn "Args passed in: %A" args
  0 // Return 0 exit code for success