val a : int

Full name: Index.a
val b : bool

Full name: Index.b
val c : string

Full name: Index.c
val range : int list

Full name: Index.range
val n : int
Multiple items
type LiteralAttribute =
  inherit Attribute
  new : unit -> LiteralAttribute

Full name: Microsoft.FSharp.Core.LiteralAttribute

--------------------
new : unit -> LiteralAttribute
val item : int * string * float

Full name: Index.item
val id : int

Full name: Index.id
val name : string

Full name: Index.name
val price : float

Full name: Index.price
val productName : string

Full name: Index.productName
val productPrice : float

Full name: Index.productPrice
val numbers : int list

Full name: Index.numbers
val result : string

Full name: Index.result
val sprintf : format:Printf.StringFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.sprintf
property List.Length: int
val nothing : 'a option

Full name: Index.nothing
union case Option.None: Option<'T>
val something : int option

Full name: Index.something
union case Option.Some: Value: 'T -> Option<'T>
val optionResult : string

Full name: Index.optionResult
val add : n1:int -> n2:int -> int

Full name: Index.add
val n1 : int
val n2 : int
val addWithTwo : (int -> int)

Full name: Index.addWithTwo
type User =
  {id: int;
   firstName: string;
   lastName: string;
   email: string;
   roles: string list option;}
  member fullname : string

Full name: Index.User
User.id: int
Multiple items
val int : value:'T -> int (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.int

--------------------
type int = int32

Full name: Microsoft.FSharp.Core.int

--------------------
type int<'Measure> = int

Full name: Microsoft.FSharp.Core.int<_>
User.firstName: string
Multiple items
val string : value:'T -> string

Full name: Microsoft.FSharp.Core.Operators.string

--------------------
type string = System.String

Full name: Microsoft.FSharp.Core.string
User.lastName: string
User.email: string
User.roles: string list option
type 'T list = List<'T>

Full name: Microsoft.FSharp.Collections.list<_>
type 'T option = Option<'T>

Full name: Microsoft.FSharp.Core.option<_>
val x : User
member User.fullname : string

Full name: Index.User.fullname
val user : User

Full name: Index.user
type Shape =
  | Square of float
  | Rectangle of float * float
  | Circle of float

Full name: Index.Shape
union case Shape.Square: float -> Shape
Multiple items
val float : value:'T -> float (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.float

--------------------
type float = System.Double

Full name: Microsoft.FSharp.Core.float

--------------------
type float<'Measure> = float

Full name: Microsoft.FSharp.Core.float<_>
union case Shape.Rectangle: float * float -> Shape
union case Shape.Circle: float -> Shape
val square : Shape

Full name: Index.square
val rectangle : Shape

Full name: Index.rectangle
val circle : Shape

Full name: Index.circle
type RoleType =
  | Admin = 0
  | Manager = 1
  | Agent = 2

Full name: Index.RoleType
RoleType.Admin: RoleType = 0
RoleType.Manager: RoleType = 1
RoleType.Agent: RoleType = 2
val role : RoleType

Full name: Index.role
Multiple items
val array : int []

Full name: Index.array

--------------------
type 'T array = 'T []

Full name: Microsoft.FSharp.Core.array<_>
Multiple items
val list : string list

Full name: Index.list

--------------------
type 'T list = List<'T>

Full name: Microsoft.FSharp.Collections.list<_>
val sequence : seq<int>

Full name: Index.sequence
Multiple items
val seq : sequence:seq<'T> -> seq<'T>

Full name: Microsoft.FSharp.Core.Operators.seq

--------------------
type seq<'T> = System.Collections.Generic.IEnumerable<'T>

Full name: Microsoft.FSharp.Collections.seq<_>
val index : string

Full name: Index.index
val squares : int list

Full name: Index.squares
val isEven : n:int -> bool

Full name: Index.isEven
val even : int list

Full name: Index.even
Multiple items
module List

from Microsoft.FSharp.Collections

--------------------
type List<'T> =
  | ( [] )
  | ( :: ) of Head: 'T * Tail: 'T list
  interface IEnumerable
  interface IEnumerable<'T>
  member GetSlice : startIndex:int option * endIndex:int option -> 'T list
  member Head : 'T
  member IsEmpty : bool
  member Item : index:int -> 'T with get
  member Length : int
  member Tail : 'T list
  static member Cons : head:'T * tail:'T list -> 'T list
  static member Empty : 'T list

Full name: Microsoft.FSharp.Collections.List<_>
val filter : predicate:('T -> bool) -> list:'T list -> 'T list

Full name: Microsoft.FSharp.Collections.List.filter
val x : int
val sortedFruit : string list

Full name: Index.sortedFruit
val sort : list:'T list -> 'T list (requires comparison)

Full name: Microsoft.FSharp.Collections.List.sort
type Person =
  {firstName: string;
   lastName: string;}

Full name: Index.Person
Person.firstName: string
Person.lastName: string
val people : Person list

Full name: Index.people
val firstNames : string list

Full name: Index.firstNames
val map : mapping:('T -> 'U) -> list:'T list -> 'U list

Full name: Microsoft.FSharp.Collections.List.map
val x : Person
val sortDescending : list:'T list -> 'T list (requires comparison)

Full name: Microsoft.FSharp.Collections.List.sortDescending
val take : count:int -> list:'T list -> 'T list

Full name: Microsoft.FSharp.Collections.List.take
val iter : action:('T -> unit) -> list:'T list -> unit

Full name: Microsoft.FSharp.Collections.List.iter
val printfn : format:Printf.TextWriterFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printfn
namespace System
namespace System.IO
val bigFiles : seq<string>

Full name: Index.bigFiles
type Directory =
  static member CreateDirectory : path:string -> DirectoryInfo + 1 overload
  static member Delete : path:string -> unit + 1 overload
  static member EnumerateDirectories : path:string -> IEnumerable<string> + 2 overloads
  static member EnumerateFileSystemEntries : path:string -> IEnumerable<string> + 2 overloads
  static member EnumerateFiles : path:string -> IEnumerable<string> + 2 overloads
  static member Exists : path:string -> bool
  static member GetAccessControl : path:string -> DirectorySecurity + 1 overload
  static member GetCreationTime : path:string -> DateTime
  static member GetCreationTimeUtc : path:string -> DateTime
  static member GetCurrentDirectory : unit -> string
  ...

Full name: System.IO.Directory
Directory.EnumerateFiles(path: string) : System.Collections.Generic.IEnumerable<string>
Directory.EnumerateFiles(path: string, searchPattern: string) : System.Collections.Generic.IEnumerable<string>
Directory.EnumerateFiles(path: string, searchPattern: string, searchOption: SearchOption) : System.Collections.Generic.IEnumerable<string>
module Seq

from Microsoft.FSharp.Collections
val map : mapping:('T -> 'U) -> source:seq<'T> -> seq<'U>

Full name: Microsoft.FSharp.Collections.Seq.map
val name : string
Multiple items
type FileInfo =
  inherit FileSystemInfo
  new : fileName:string -> FileInfo
  member AppendText : unit -> StreamWriter
  member CopyTo : destFileName:string -> FileInfo + 1 overload
  member Create : unit -> FileStream
  member CreateText : unit -> StreamWriter
  member Decrypt : unit -> unit
  member Delete : unit -> unit
  member Directory : DirectoryInfo
  member DirectoryName : string
  member Encrypt : unit -> unit
  ...

Full name: System.IO.FileInfo

--------------------
FileInfo(fileName: string) : unit
val filter : predicate:('T -> bool) -> source:seq<'T> -> seq<'T>

Full name: Microsoft.FSharp.Collections.Seq.filter
val fi : FileInfo
property FileInfo.Length: int64
property FileInfo.Name: string

F#

Kornelije Sajler

Blog: learnaholic.me

Photography: ksphoto.me

Binding

1: 
let a = 5
5
1: 
2: 
5 = a
let b = 5 = a
true
1: 
2: 
3: 
4: 
5: 
let c =
  if a < 5 then
    "Less than"
  else
    "Greater than"
"Greater than"

Binding cont.

1: 
2: 
3: 
4: 
5: 
let range =
  [
    for n in  1..10 ->
      n * 2
  ]
[2; 4; 6; 8; 10; 12; 14; 16; 18; 20]

Module, Namespace, Attribute, Constant

1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
namespace SuperApp
[<Literal>]
let meaningOfLife = 42

module Util =
  let crackIt = ()

let doCracking = Util.crackIt

Tuple

1: 
2: 
3: 
let item = (1, "apple", 2.99)
let id, name, price = item
let _, productName, productPrice = item
1
"apple"
2.99

Pattern Matching

1: 
2: 
3: 
4: 
5: 
6: 
let numbers = [ 1..10 ]

let result =
  match numbers with
  | [] -> "Nothing in collection"
  | _ -> sprintf "Collection count: %i" numbers.Length
"Collection count: 10"

Option

1: 
2: 
3: 
4: 
5: 
6: 
7: 
let nothing = None
let something = Some 1

let optionResult =
  match something with
  | None -> "nothing something"
  | Some n -> sprintf "something: %i" n
"something: 1"

Function

1: 
2: 
3: 
4: 
let add n1 n2 =
  n1 + n2

add 1 2
3

Partial Application

1: 
2: 
3: 
let addWithTwo = (+) 2

addWithTwo 4
6

Record

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
type User = {
  id: int
  firstName: string
  lastName: string
  email: string
  roles: string list option
}
with member x.fullname = sprintf "%s %s" x.firstName x.lastName

let user = {
  id = 1
  firstName = "pero"
  lastName = "peric"
  email = "pero@ab.ba"
  roles = None
}
"pero peric"

Discriminated Unions

1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
type Shape =
  | Square of float
  | Rectangle of float * float
  | Circle of float

let square = Square 3.
let rectangle = Rectangle(2., 1.5)
let circle = Circle(1.0)
Rectangle (2.0,1.5)

Enum

1: 
2: 
3: 
4: 
5: 
6: 
type RoleType =
  | Admin = 0
  | Manager = 1
  | Agent = 2

let role = RoleType.Admin
Admin

Collections

1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
let array = [| 1; 2; 4 |]
let list = [
  "apple"
  "orange"
  "peach"
]
let sequence = seq { 0..99 }
let index = list.[0]
[|1; 2; 4|]
["apple"; "orange"; "peach"]
seq [0; 1; 2; 3; ...]
"apple"

For & Yield

1: 
2: 
3: 
let squares = [
  for n in 0..99 do
    yield n * n ]
[0; 1; 4; 9; 16; 25; 36; 49; 64; 81; 100; 121; 144; 169; 196; 225; 256; 289; 324;
 361; 400; 441; 484; 529; 576; 625; 676; 729; 784; 841; 900; 961; 1024; 1089;
 1156; 1225; 1296; 1369; 1444; 1521; 1600; 1681; 1764; 1849; 1936; 2025; 2116;
 2209; 2304; 2401; 2500; 2601; 2704; 2809; 2916; 3025; 3136; 3249; 3364; 3481;
 3600; 3721; 3844; 3969; 4096; 4225; 4356; 4489; 4624; 4761; 4900; 5041; 5184;
 5329; 5476; 5625; 5776; 5929; 6084; 6241; 6400; 6561; 6724; 6889; 7056; 7225;
 7396; 7569; 7744; 7921; 8100; 8281; 8464; 8649; 8836; 9025; 9216; 9409; 9604;
 9801]

Filter & Pipe

1: 
2: 
let isEven n = n % 2 = 0
let even = squares |> List.filter (fun x -> isEven x)
[0; 4; 16; 36; 64; 100; 144; 196; 256; 324; 400; 484; 576; 676; 784; 900; 1024;
 1156; 1296; 1444; 1600; 1764; 1936; 2116; 2304; 2500; 2704; 2916; 3136; 3364;
 3600; 3844; 4096; 4356; 4624; 4900; 5184; 5476; 5776; 6084; 6400; 6724; 7056;
 7396; 7744; 8100; 8464; 8836; 9216; 9604]

Sort

1: 
let sortedFruit = List.sort [ "pear"; "orange"; "apple" ]
["apple"; "orange"; "pear"]

Map

1: 
2: 
3: 
4: 
5: 
6: 
7: 
type Person = { firstName: string; lastName: string }
let people = [
  { firstName = "pero"; lastName = "peric" }
  { firstName = "djuro"; lastName = "djuric" }
  { firstName = "ivo"; lastName = "ivic" } ]

let firstNames = people |> List.map (fun x -> x.firstName)
[{firstName = "pero";
  lastName = "peric";}; {firstName = "djuro";
                         lastName = "djuric";}; {firstName = "ivo";
                                                 lastName = "ivic";}]

Multiple pipes

1: 
2: 
3: 
4: 
5: 
squares
|> List.filter isEven
|> List.sortDescending
|> List.take 5
|> List.iter (fun n -> printfn "%i" n)
[9604; 9216; 8836; 8464; 8100]

Sequence example

1: 
2: 
3: 
4: 
5: 
6: 
7: 
open System.IO

let bigFiles =
  Directory.EnumerateFiles(@"/Applications/Mail.app/Contents/Resources")
  |> Seq.map (fun name -> FileInfo name)
  |> Seq.filter (fun fi -> fi.Length > 10000L)
  |> Seq.map (fun fi -> fi.Name)
seq
  ["ActionFlagTemplate.pdf"; "ActionReadTemplate.pdf";
   "ActionReplyAllTemplate.pdf"; "ActionUnreadTemplate.pdf"; ...]

Pros

  • Readability and joy to write
  • First class function
  • Powerful type inference and true strong typed language
  • Piping
  • Patern matching
  • Collections builtin (no namespace imports needed)
  • Option (hard to get null reference exception)
  • Have modules and namespaces
  • Usual OOP Design Patterns = Function in F#
  • Functionl (proper) and OOP
  • Type Provider

Cons

  • Not easy to start for usual OOP developer
  • Part of .NET Framework (which is OOP and C# oriented)
  • Dealing with C# - espcially "functional C#" Action<T> and Func<T>
  • Mostly any proven library is C# based
  • Abandoned by Microsoft (more emphasis on node.js and even C++)
  • Part of .NET Languages
  • Lacking of Visual Studio support (as C#/node.js/C++ have)
    • Some funky errors, not easy to comprehend

Real life examples

Questions?!

Slides