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
Complexity causes
- State
- Flow of control
- Code volume
So we tried F#
- 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
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)
|
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"
|
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
Books
- Expert F#
- Real World Functional programming
- More Books
Thanks :D