Multiple items
module List

from Microsoft.FSharp.Collections

--------------------
type List<'T> =
  | ( [] )
  | ( :: ) of Head: 'T * Tail: 'T list
  interface IEnumerable
  interface IEnumerable<'T>
  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 sum : list:'T list -> 'T (requires member ( + ) and member get_Zero)

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

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printfn
val square : x:int -> int

Full name: Document.square
val x : int
val sq : int

Full name: Document.sq
type Person =
  {First: string;
   Last: string;}

Full name: Document.Person
Person.First: 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
Person.Last: string
type Employee =
  | Worker of Person
  | Manager of Employee list

Full name: Document.Employee
union case Employee.Worker: Person -> Employee
union case Employee.Manager: Employee list -> Employee
type 'T list = List<'T>

Full name: Microsoft.FSharp.Collections.list<_>
val triple : x:int -> int

Full name: Document.triple
val tripleSquared : (int -> int)

Full name: Document.tripleSquared
val fibonacci : n:int -> int

Full name: Document.fibonacci
val n : int
val unlockAchievement : gameObject:'a -> achivement:'b -> unit

Full name: Document.unlockAchievement
val gameObject : 'a
val achivement : 'b
val character : obj
val not : value:bool -> bool

Full name: Microsoft.FSharp.Core.Operators.not
val keyboard : 'a
active recognizer SpaceKey: 'a -> 'b

Full name: Document.( |SpaceKey| )
active recognizer Hold100ms: 'a -> 'b

Full name: Document.( |Hold100ms| )
namespace System
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<_>

The tools that shape us

Andrea Magnorsky @ λ Days

Digital Furnace Games ▀ BatCat Games ▀ GameCraft Foundation

Working on OniKira: Demon Killer

Available on Steam Early Access

Working on OniKira: Demon Killer

Steam Early Access

Why?

tar pit

Out of the tar pit - Mosley, Marks 2006

pic src http://en.wikipedia.org/wiki/McKittrick_Tar_Pits

Complexity causes

  • State
  • Flow of control
  • Code volume

Simple is hard

So we tried F#

fs
  • Functional first
  • .net Interop
  • Concise
  • Type system
  • OSS
  • Cross platform
  • Divine learning curve
 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
// one-liners
[1..100] |> List.sum |> printfn "sum=%d"

// no curly braces, semicolons or parentheses
let square x = x * x
let sq = square 42 

// simple types in one line
type Person = {First:string; Last:string}

// complex types in a few lines
type Employee = 
  | Worker of Person
  | Manager of Employee list

let square x = x * x
let triple x = x * 3
let tripleSquared  = square >> triple

Visit F# for Fun and Profit for more examples and knowledge

What we use

pattern-matching

1: 
2: 
3: 
4: 
5: 
let rec fibonacci n =
    match n with
    | 0 -> 0
    | 1 -> 1
    | _ -> fibonacci (n - 1) + fibonacci (n - 2)
 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
let unlockAchievement gameObject achivement=
    match gameObject.GetComponent<CharacterController>() with 
    | null -> ()
    | character -> 
        if (not character.IsOnGround()) then 
            PlatformHelper.UnlockAchievement achivement
            this.GameObj.GetComponent<ScriptComponent>().DisposeLater()

match msg with                
| :? ActorDiedMessage as diedMessage -> 
           unlockAchievement diedMessage.GameObj GameAchivement.AirKill
| _ -> ()

Active Patterns

1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
9: 
let (|SpaceKey|) (keyboard:KeyboardInput) = 
    keyboard.KeyPressed(Key.Space)

let (|Hold100ms|) (keyboard:KeyboardInput) = 
    keyboard.KeyPressedFor(Key.I, 100)  

match DualityApp.Keyboard with        
| SpaceKey true & Hold100ms false -> playerGo Jump
| SpaceKey true & Hold100ms true -> playerGo DoubleJump
 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
let (|LeftKey|RightKey|OtherKey|) (keyboard:KeyboardInput) = 
    if keyboard.KeyPressed(Key.Left) then LeftKey
    elif keyboard.KeyPressed(Key.Right) then RightKey
    else OtherKey "Hi, you pressed a key...well that is interesting :D"

interface ICmpUpdatable with
    member this.OnUpdate()=        
        match DualityApp.Keyboard with            
        | LeftKey  -> playerGo Left
        | RightKey-> playerGo Right
        | OtherKey s-> ()

Interop

Check out the design guidelines

C# consuming F# code

Use namespaces in F# or prefix with global::YourModuleName

using System;
class Program
{
    static void Main(string[] args)
    {
        var s = Calculator.Calc.add("4 4", "+");
        Console.WriteLine("The sum is {0}", s);
    }
}

and the F# side

1: 
2: 
3: 
4: 
5: 
6: 
namespace Calculator
module Calc =

    open System
    let add numbers delimiter =    
        // Do stuff to add numbers            

F# consuming C# code

1: 
2: 
3: 
4: 
5: 
6: 
module MathTest =

open NUnit.Framework

let [<Test>] ``2 + 2 should equal 4``() =
    Assert.AreEqual(2 + 2, 4)

REPL

Now: exploration

Future: Live coding

Ecosystem: What we use now

  • FsCheck
  • Fake
  • Compiler Services

Property Testing with FsCheck

Why write tests, when you can generate them

What is a property?

x + x = 2 * x

or

List.rev(List.rev list) = list

FsCheck

  • QuickCheck paper by Koen Claessen and John Hughes
  • Superb article by Scott Wlaschin on Property based testing as part of the F# advent calendar.
  • Can be used from C#
  • Small library
  • Can run stand alone or integrates with NUnit and xUnit
1: 
2: 
3: 
[<Property>]
let ``When adding x to x then result is double x``(x:int)=
    x + x = 2*x
1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
let preconditionMaxHealth maxHealth = maxHealth > 0

[<Property(Verbose = true)>]    
let ``Health should never be higher than max`` (x:int)(maxHealth:int)=        
    let healthComponent = initedHealth
    healthComponent.MaxHealth <- maxHealth
    healthComponent.IncreaseHealth x
    preconditionMaxHealth maxHealth ==>  (healthComponent.MaxHealth >= healthComponent.Health)
fs

Fake : F# Make

  • Use from any .net language
  • It's mature.
  • Builds for .net and mono, it's cross platform.
  • No need to know F# to use it.
  • Integrates with CI Server.

Hello world!

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
// include Fake lib
#r @"tools\FAKE\tools\FakeLib.dll"
open Fake 
Target "Foo" (fun _ ->
    trace "Hello World from Foo"
)

Target "Bar" (fun _ -> 
    trace "Hello World from Bar"
)
"Bar"
  ==> "Foo"

RunTargetOrDefault "Foo"

Real world

Compiler.Services

Use compiler service to compile a file into an assembly that is inmediately consumed by the game engine Duality.

Duality.Scripting

  • File watcher
  • Code in any editor :)
  • Compiler Services call to fsc
  • Future -> live coding

repo

fs

Resources

Books

  • Expert F#
  • Real World Functional programming
  • More Books

Events

  • F# Exchange (17th April - London)
  • NCrafts (21-22 May - Paris)

  • User groups FK

Thanks :D

onikira

Links