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<_>

Functional Programming in games ... with F#

Andrea Magnorsky @ Digital Dragons

fs

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

fs
tar pit

Out of the tar pit - Mosley, Marks 2006

pic src

Complexity causes

  • State
  • Flow of control
  • Code volume
fs

Simple is hard

With Lisp, one can rapidly develop meta constructs for behaviors and combine them in new ways. In addition, Lisp allows the redefinition of the language to easily add new constructs; particularly those needed to deal with time-based behaviors and layering of actions....

Contrary to popular belief, there is nothing inherently slow about Lisp. It is easy to construct a simple dialect which is just as efficient as C, but retains the dynamic and consistent qualities that make Lisp a much more effective expression of one’s programming intentions.

Andy Gavin, Naughty Dog co-founder Sauce

So we tried F#

fs
  • Functional first
  • .net Interop
  • Type system
  • OSS
  • Cross platform
  • Divine learning curve

What does it look like?

 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 .
  • 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#
  • Programming F#
  • Real World Functional programming
  • More Books

Events

  • User groups FK

Thanks :D

onikira

Links