F# from the C# point of view

 

Michal Franc

Pragmatic Developer @ JustGiving

www.mfranc.com

@francmichal

Agenda

 

  • Functional vs C#-like
  • Lot's of samples C# vs F#
  • Some F# magic

Imperative      vs     Functional

no implicit mutation

recurrence, functions, pattern matchin

functions, record types, union types, function compostion

 

mutable data

loops, functions, if statements

objects, structs

inheritance, composition, polimorphism

Functional C#

Linq - declarative + functional

Anonymous functions

lambda / delegate 

type inference - var, dynamic

tuple

generics

C# 

Hybrid with a more emphasis on object oriented world

F#

Hybrid with a more emphasis on functional world

Why F# ?

  • immutability by default
  • hybrid
  • step by step functional
  • .NET interop
  • VS support

Blockers

  • syntax
  • platform
  • hard stuff
  • OOP experience
  • addiction to mutable state
  • Functional Thinking
  • intuition / prior experience
  • R#

Into the Functional World

C# vs F#

Demo

List counter

C# - count

var current = 0;

foreach(elem in list) {
    current++;
}
List - Count

public void Add(T item) {
            if (_size == _items.Length) EnsureCapacity(_size + 1);
            _items[_size++] = item;
            _version++;
        }

F# - count

Mutable state

let list = [1..100]

let count list =
    let mutable counter = 0;
    for i in list do
        counter <- counter + 1
    counter
        
count list

F# - count

let list = [1..10000000]

let rec count list =
    match list with
        | i::tail -> 1 + (count tail)
        | [] -> 0
        
count list       

Recursion!

StackOverflow!

F# - count

let list = [1..10000000]

let rec count acc list =
    match list with
        | i::tail -> (count (acc + 1) tail)
        | [] -> acc
        
count 0 list     

Tail Recursion

Demo

Encapsulation

 C# - object

    public class Human
    {
        public int Life { get; set; }

        public Human()
        {
            this.Life = 100;
        }

        public void TakeHit(int val)
        {
            this.Life -= val;
        }
    }

 F# - object

type Human() =
     let mutable _life = 100
     member this.takeHit value = _life <- _life - value
     member this.Life
            with get () = _life

let human = new Human()
type Human(life) =
     let _life = life
     member this.takeHit value = new Human(_life - value)
     member this.Life
            with get () = _life

human.takeHit 10
human.Life
let human = new Human(100)
let newHuman = human.takeHit 10
newHuman.Life

F# - record type 

type Item = {
    Id : int
    Name : string
    IsAwesome : bool
    IsActive : bool 
}
let createDefault = {
    Id = 1
    Name = "first"
    IsAwesome = true
    IsActive = true
} 
let first = { createDefault with Name = "first" }
let second = { first with Quantity = 5 }
let third = { second with IsActive = false; IsAwesome = false }
let isAwesomeButNotActive item = 
    match item with
    | { IsActive = false; IsAwesome = true } -> true
    | _ -> false
    
isAwesomeButNotActive { createDefault with IsActive = false }

F# - record type

type Human = {
    Life : int
}

let createNew = {
    Life = 100
}

let takeHit value human = {
    human with Life = human.Life - value
}

let human = createNew
let newHuman = takeHit 10 human

F# - record type

type Human = {
    Life : int
} with member this.takeHit value = {
    this with Life = this.Life - value
}

let createNew = {
    Life = 100
}

let human = createNew
let newHuman = human.takeHit 10

C# - edge cases

public void TakeHit(int val)
{
    if (val < 0) throw new ArgumentOutOfRangeException();

    this.Life -= val;

    if (this.Life < 0) this.Life = 0;
}

F# - edge cases

let takeHit value human = 
    if value < 0 then raise (System.ArgumentException())
    {
        human with Life = if (human.Life - value) < 0 
                          then 0 else human.Life - value
    }
let takeHit value human = 
    if value < 0 then invalidArg "value" "cannot be less than 0"
    ...

F# - edge cases

let takeHit value human = 
    if value < 0 then invalidArg "value" "cannot be less than 0"
    {
        human with Life = match (human.Life, value) with
                            | (l, v) when l - v < 0 -> 0
                            | (l, v) -> l - v
    }
let takeHit value human = 
    if value < 0 then invalidArg "value" "cannot be less than 0"
    {
        human with Life = match human.Life - value with
                            | difference when difference < 0 -> 0
                            | difference -> difference
    }

C#

public void Attack(Human target)
{
     target.TakeHit(this.Strength); 
}
public void Attack(Human target)
{
     target.TakeHit(this.Strength);
     this.Stamina -= 10;
     if (this.Stamina < 0) this.Stamina = 0;
}
public void Attack(Human target)
{
    if (this.Stamina - 10 < 0) return;

    target.TakeHit(this.Strength);
    this.Stamina -= 10;
    if (this.Stamina < 0) this.Stamina = 0;
}

F#

let attackTarget human target =
    takeHit human.Strength target
let attackTarget human target =
    (
        takeHit human.Strength target, 
        { human with Stamina = human.Stamina - 10 }
    )

let human = createNew
let target = createNew
let (newHuman, newTarget) = attackTarget human target
let difference0 one two = match one - two with
                            | difference when difference < 0 -> 0
                            | difference -> difference 
let attackTarget human target =
    (
        takeHit human.Strength target, 
        { human with Stamina = difference0 human.Stamina 10 }
    )
let private (-@) one two = match one - two with
                            | difference when difference < 0 -> 0
                            | difference -> difference 
let attackTarget human target =
    (
        takeHit human.Strength target, 
        { human with Stamina = human.Stamina -@ 10 }
    )

NULL in F#

*it is possible just like pointers in C#

[<AllowNullLiteral>] - interop

F# Patterns

let basic item =
    printf "%i" item
    
let newLine item =
    printf "\n%i" item

type Strategy(displayFunction) = 
    member this.DisplayFunction list = 
            List.iter displayFunction list

Strategy(basic).DisplayFunction [1..6]
Strategy(newLine).DisplayFunction [1..6]

F# Patterns

type A private () =
    static let instance = A()
    static member Instance = instance
    member this.Action() = printfn "singleton"

A.Instance.Action()

F# Interfaces

type ICalc = 
    abstract member Calc: int -> int -> int
    
type Calculator() =
    interface ICalc with 
        member this.Calc x y = 
            x + y
         
type ICalc = 
    abstract member Calc: int -> int -> int

let addCalc = 
    { new ICalc with member this.Calc x y = x + y }
        
let calc = addCalc
calc.Calc 1 1
let calc = new Calculator() :> ICalc
calc.Calc 1 1

F# Interfaces

type CalcService = {
    Add : int -> int -> int
    Substract : int -> int -> int
    Multiply : int -> int -> int
    Divide : int -> int -> int
}

let service = {
    Add = fun x y -> x + y
    Substract = fun x y -> x - y
    Multiply = fun x y -> x * y
    Divide = fun x y -> x / y
}

C# Interfaces

public class ImageRepo
{
   private IImageProvider imageProvider;

   public ImageRepo(IImageProvider imageProvider)
   {
        this.imageProvider = imageProvider;
   }

   public byte[] GetImage(string imageName)
   {
       return this.imageProvider.GetImage(imageName);
   }
}

var fromDB = new ImageRepo(new IMageFromDataBaseProvider());
var fromUrl = new ImageRepo(new IMageFromUrlProvider());
var fromSrv = new ImageRepo(new IMageFromFileProvider());

F# Interfaces

type ImageFrom = URL | SRV | DB

let imageRepoBuilder imageFrom =
    match imageFrom with
    | URL -> imageRepo imageFromUrl
    | SRV -> imageRepo imageFromSrv
    | DB -> imageRepo imageFromDb
 
let imageFrom imageType name =
    imageRepoBuilder imageType name
    
imageFrom URL "test.jpg"
imageFrom DB "test.jpg"
imageFrom SRV "test.jpg"

http://i.imgur.com/FLf5J6f.jpg

QA

More

http://fsharpforfunandprofit.com/

http://fsharpforfunandprofit.com/rop/

http://www.tryfsharp.org/

http://www.amazon.com/Real-World-Functional-Programming-With-Examples/dp/1933988924

http://fsharp.org/

https://sergeytihon.wordpress.com/category/f-weekly/

http://www.cs.uni.edu/~wallingf/blog-images/computing/make-let-not-var-small.jpg

End

Michal Franc

www.mfranc.com

@francmichal

Fnctional Way - C# to F#

By Michal Franc

Fnctional Way - C# to F#

From OOP to Functional Programming [ENG]

  • 1,713