val maybe : (obj -> obj) Full name: index.maybe
val addNUmbers : obj Full name: index.addNUmbers
union case Option.Some: Value: 'T -> Option<'T>
namespace System
val sleepWorkflow : Async<unit> Full name: index.sleepWorkflow
val async : AsyncBuilder Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.async
val printfn : format:Printf.TextWriterFormat<'T> -> 'T Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printfn
Multiple items type DateTime = struct new : ticks:int64 -> DateTime + 10 overloads member Add : value:TimeSpan -> DateTime member AddDays : value:float -> DateTime member AddHours : value:float -> DateTime member AddMilliseconds : value:float -> DateTime member AddMinutes : value:float -> DateTime member AddMonths : months:int -> DateTime member AddSeconds : value:float -> DateTime member AddTicks : value:int64 -> DateTime member AddYears : value:int -> DateTime ... end Full name: System.DateTime -------------------- DateTime() (+0 other overloads) DateTime(ticks: int64) : unit (+0 other overloads) DateTime(ticks: int64, kind: DateTimeKind) : unit (+0 other overloads) DateTime(year: int, month: int, day: int) : unit (+0 other overloads) DateTime(year: int, month: int, day: int, calendar: Globalization.Calendar) : unit (+0 other overloads) DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int) : unit (+0 other overloads) DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, kind: DateTimeKind) : unit (+0 other overloads) DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, calendar: Globalization.Calendar) : unit (+0 other overloads) DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int) : unit (+0 other overloads) DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int, kind: DateTimeKind) : unit (+0 other overloads)
property DateTime.Now: DateTime
property DateTime.TimeOfDay: TimeSpan
Multiple items type Async static member AsBeginEnd : computation:('Arg -> Async<'T>) -> ('Arg * AsyncCallback * obj -> IAsyncResult) * (IAsyncResult -> 'T) * (IAsyncResult -> unit) static member AwaitEvent : event:IEvent<'Del,'T> * ?cancelAction:(unit -> unit) -> Async<'T> (requires delegate and 'Del :> Delegate) static member AwaitIAsyncResult : iar:IAsyncResult * ?millisecondsTimeout:int -> Async<bool> static member AwaitTask : task:Task<'T> -> Async<'T> static member AwaitWaitHandle : waitHandle:WaitHandle * ?millisecondsTimeout:int -> Async<bool> static member CancelDefaultToken : unit -> unit static member Catch : computation:Async<'T> -> Async<Choice<'T,exn>> static member FromBeginEnd : beginAction:(AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T> static member FromBeginEnd : arg:'Arg1 * beginAction:('Arg1 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T> static member FromBeginEnd : arg1:'Arg1 * arg2:'Arg2 * beginAction:('Arg1 * 'Arg2 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T> static member FromBeginEnd : arg1:'Arg1 * arg2:'Arg2 * arg3:'Arg3 * beginAction:('Arg1 * 'Arg2 * 'Arg3 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T> static member FromContinuations : callback:(('T -> unit) * (exn -> unit) * (OperationCanceledException -> unit) -> unit) -> Async<'T> static member Ignore : computation:Async<'T> -> Async<unit> static member OnCancel : interruption:(unit -> unit) -> Async<IDisposable> static member Parallel : computations:seq<Async<'T>> -> Async<'T []> static member RunSynchronously : computation:Async<'T> * ?timeout:int * ?cancellationToken:CancellationToken -> 'T static member Sleep : millisecondsDueTime:int -> Async<unit> static member Start : computation:Async<unit> * ?cancellationToken:CancellationToken -> unit static member StartAsTask : computation:Async<'T> * ?taskCreationOptions:TaskCreationOptions * ?cancellationToken:CancellationToken -> Task<'T> static member StartChild : computation:Async<'T> * ?millisecondsTimeout:int -> Async<Async<'T>> static member StartChildAsTask : computation:Async<'T> * ?taskCreationOptions:TaskCreationOptions -> Async<Task<'T>> static member StartImmediate : computation:Async<unit> * ?cancellationToken:CancellationToken -> unit static member StartWithContinuations : computation:Async<'T> * continuation:('T -> unit) * exceptionContinuation:(exn -> unit) * cancellationContinuation:(OperationCanceledException -> unit) * ?cancellationToken:CancellationToken -> unit static member SwitchToContext : syncContext:SynchronizationContext -> Async<unit> static member SwitchToNewThread : unit -> Async<unit> static member SwitchToThreadPool : unit -> Async<unit> static member TryCancelled : computation:Async<'T> * compensation:(OperationCanceledException -> unit) -> Async<'T> static member CancellationToken : Async<CancellationToken> static member DefaultCancellationToken : CancellationToken Full name: Microsoft.FSharp.Control.Async -------------------- type Async<'T> Full name: Microsoft.FSharp.Control.Async<_>
static member Async.Sleep : millisecondsDueTime:int -> Async<unit>
static member Async.RunSynchronously : computation:Async<'T> * ?timeout:int * ?cancellationToken:Threading.CancellationToken -> 'T
val job : obj Full name: index.job
val sprintf : format:Printf.StringFormat<'T> -> 'T Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.sprintf
type Environment = static member CommandLine : string static member CurrentDirectory : string with get, set static member Exit : exitCode:int -> unit static member ExitCode : int with get, set static member ExpandEnvironmentVariables : name:string -> string static member FailFast : message:string -> unit + 1 overload static member GetCommandLineArgs : unit -> string[] static member GetEnvironmentVariable : variable:string -> string + 1 overload static member GetEnvironmentVariables : unit -> IDictionary + 1 overload static member GetFolderPath : folder:SpecialFolder -> string + 1 overload ... nested type SpecialFolder nested type SpecialFolderOption Full name: System.Environment
property Environment.MachineName: string
val makeJob : i:'a -> 'b Full name: index.makeJob
val i : 'a
val failwith : message:string -> 'T Full name: Microsoft.FSharp.Core.Operators.failwith
val jobs2 : obj list Full name: index.jobs2
val i : int
type Colour = {r: byte; g: byte; b: byte; a: byte;} Full name: index.Colour
Colour.r: byte
Multiple items val byte : value:'T -> byte (requires member op_Explicit) Full name: Microsoft.FSharp.Core.Operators.byte -------------------- type byte = Byte Full name: Microsoft.FSharp.Core.byte
Colour.g: byte
Colour.b: byte
Colour.a: byte
val addTwo : c1:Colour -> c2:Colour -> Colour Full name: index.addTwo
val c1 : Colour
val c2 : Colour
type Monoid<'a> = {neutral: 'a; op: 'a -> 'a -> 'a;} Full name: index.Monoid<_>
Monoid.neutral: 'a
Monoid.op: 'a -> 'a -> 'a
val black : Colour Full name: index.black
val colourAdd : Monoid<Colour> Full name: index.colourAdd
val c1 : Colour Full name: index.c1
val c2 : Colour Full name: index.c2
val l : Colour Full name: index.l
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 reduce : reduction:('T -> 'T -> 'T) -> list:'T list -> 'T Full name: Microsoft.FSharp.Collections.List.reduce
type T = Colour Full name: index.T
val M : Monoid<Colour> Full name: index.M
val Z : Colour Full name: index.Z
Monoid.neutral: Colour
Monoid.op: Colour -> Colour -> Colour
val ( Z is the neutral element ) : v:T -> bool Full name: index.( Z is the neutral element )
val v : T
val ( The op is associative ) : a:T * b:T * c:T -> bool Full name: index.( The op is associative )
val a : T
val b : T
val c : T
val division : a:int -> b:int -> c:int -> d:int -> int option Full name: index.division
val a : int
val b : int
val c : int
val d : int
union case Option.None: Option<'T>
val divide : a:int -> b:int -> int option Full name: index.divide
Multiple items type MaybeBuilder = new : unit -> MaybeBuilder member Bind : value:'b option * func:('b -> 'c option) -> 'c option member Return : value:'a -> 'a option Full name: index.MaybeBuilder -------------------- new : unit -> MaybeBuilder
member MaybeBuilder.Bind : value:'b option * func:('b -> 'c option) -> 'c option Full name: index.MaybeBuilder.Bind
val value : 'b option
val func : ('b -> 'c option)
val value : 'b
val __ : MaybeBuilder
member MaybeBuilder.Return : value:'a -> 'a option Full name: index.MaybeBuilder.Return
val value : 'a
val maybe : MaybeBuilder Full name: index.maybe
val divisionM : a:int -> b:int -> c:int -> d:int -> int option Full name: index.divisionM
val x : int
val y : int
val z : int
val ( monad laws ) : unit -> 'a Full name: index.( monad laws )
val ret : (int -> 'b)
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<_>
val n : (string -> string)
val m : 'b
val f : 'c
val f : (int -> obj)
val x : obj
val f : (obj -> obj)
val g : obj
val v : obj
val a : obj
val b : obj
Computation expressions in context
Lambda World - October 2015
Andrea Magnorsky
Digital Furnace Games ▀ BatCat Games ▀ GameCraft Foundation
introduce comp expressions
Computation Expressions
1:
2:
3:
4:
5:
6:
7:
8:
let maybe = new MaybeBuilder ()
let addNUmbers =
maybe {
let x = 12
let! y = Some 11
let! z = Some 30
return x + y + z
}
Block of code that represent a computation with a non standard aspect
build your own
code inside the block is reinterpreted using a computation builder
record of operations that define the semantics and syntax
async
1:
2:
3:
4:
5:
6:
7:
8:
9:
open System
let sleepWorkflow = async {
printfn "Starting at %O " DateTime . Now . TimeOfDay
do! Async . Sleep 2000
printfn "Finished at %O " DateTime . Now . TimeOfDay
}
Async . RunSynchronously sleepWorkflow
mbrace
1:
2:
3:
4:
5:
let job =
cloud {
return sprintf
"run on worker '%s' " Environment . MachineName }
|> runtime . CreateProcess
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
let makeJob i =
cloud {
if i % 8 = 0 then failwith "fail"
let primes = Sieve . getPrimes 1000000
return sprintf
"calculated %d primes %A on machine '%s'"
primes . Length
primes
Environment . MachineName
}
let jobs2 =
[ for i in 1 .. 10 ->
makeJob i |> cluster . CreateProcess ]
example source
read -> maths heavy
first person to describe monads for functional programming was Eugenio Moggi, paper called ["Notions of computation and monads"](http://www.disi.unige.'it/person/MoggiE/ftp/ic91.pdf) this paper is maths heavy tho I am sure some of you will be interested in looking at this.
Notions of computation and monads (1991)
Philip Wadler, these papers made monads in programming widely known.
Comprehending Monads (1990)
Monads for functional programming (1995)
purity vs impurity and how when trying to keep pure certain things become harder than they would be in imperative code
F# is an impure language
Pure language: it has referential transparency, so, you can replace any expression with its value without changing the meaning of the program.
Some not-useful-right-away info
There is a strong link between monads and category theory
Monads have 3 monadic laws that every monad must satisfy:
Left identity
Right identity and
Associativity
Monads eh?
lots of noise many monads tutorials
f# not a pure language
Monoids
understand monoids, the reason for that is that they made me think about program flow
why bother?
Convert pairwise operations into work in collections
Parallelization and Incrementalism
Monoids
Closures \(a' \rightarrow a' \rightarrow a'\) (example int -> int -> int )
Identity \(x + I = x\)
Associativity \(x + (y + z) = (x + y ) + z\)
1:
2:
3:
4:
5:
6:
7:
8:
type Colour = { r : byte ; g : byte ; b : byte ; a : byte }
let addTwo c1 c2 = {
r = c1 . r + c2 . r
g = c1 . g + c2 . g
b = c1 . b + c2 . b
a = c1 . a + c2 . a
}
1:
2:
3:
type Monoid < ' a > =
{ neutral : ' a
op : ' a -> ' a -> ' a }
1:
2:
3:
4:
5:
6:
let black = { r = 0uy ; g = 0uy ; b = 0uy ; a = 0uy }
let colourAdd : Monoid < Colour > = {
neutral = black
op = (addTwo )
}
1:
2:
3:
4:
5:
let c1 = { black with g = 254uy }
let c2 = { black with r = 254uy }
let l = [ c1 ; c2 ; black ]
|> List . reduce (addTwo )
Oh, yes and you can property check that your type is a monoid!!
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
type T = Colour
let M = colourAdd
let Z = M . neutral
let (++ ) = M . op
[<Property >]
let `` Z is the neutral element`` (v : T ) =
Z ++ v = v && v ++ Z = v
[<Property >]
let ``The op is associative`` (a : T , b : T , c : T ) =
a ++ (b ++ c ) = (a ++ b ++ c )
Because of closures-> We can convert pairwise operations into operations that work on collections
Because of associativity -> We can implement divide and conquer algorithms that are great for
Parallelization
Incrementalism
Because of identity -> we can actually perform certain of the above
A monad is a monoid in the category of endofunctors.
A monad is like a burrito.
Think of monads just like you would think about Legos.
It all seemed pretty strange to me and I wound up understanding less and less
then I see this in the news!! Is there some sort of link between otters and monads?
Wadler talked about handling errors in his monad paper, MAYBE we should try to write some code and see how can we use this stuff
Errors
1:
2:
3:
4:
5:
6:
7:
8:
let division a b c d =
match b with
| 0 -> None
| _ -> match c with
| 0 -> None
| _ -> match d with
| 0 -> None
| _ -> Some (((a / b )/ c )/ d )
1. Extract the core
1:
2:
3:
4:
let divide a b =
match b with
| 0 -> None
| _ -> Some (a / b )
2. Write the Builder
1:
2:
3:
4:
5:
6:
type MaybeBuilder () =
member __ . Bind (value , func ) =
match value with
| Some value -> func value
| None -> None
member __ . Return value = Some value
3. Profit
1:
2:
3:
4:
5:
6:
7:
8:
9:
let maybe = MaybeBuilder ()
let divisionM a b c d =
maybe {
let! x = divide a b
let! y = divide x c
let! z = divide y d
return z
}
what is happening here ?
Monads apply a function that returns a wrapped value to a wrapped value. Monads have a function >>= (pronounced “bind”) to do this.
oh, oh! and you can also property check a monad (tho a little harder to read than the monoids)
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
[<Test >]
let ``monad laws`` () =
let ret (x : int ) = choose . Return x
let n = sprintf "Choice : monad %s "
let inline (> > = ) m f = choose . Bind (m ,f )
fsCheck "left identity" <|
fun f a -> ret a > > = f = f a
fsCheck "right identity" <|
fun x -> x > > = ret = x
fsCheck "associativity" <|
fun f g v ->
let a = (v > > = f ) > > = g
let b = v > > = (fun x -> f x > > = g )
a = b
Why learn this?
how many of you read about DDD's ubiquitous language?
Because understanding the abstraction and having a common language is worth it
enables pure FP to represent non functions such as IO, state
control side effect (via the type system)
metaprogramming (haskell, c++ via templates)
Computation Expressions
Most monads are computation expressions, not all computation expressions are monads
let, for and try .. with, but with a different semantics
Computation expressions or workflows
Computation expressions have been available in F# since 2007 and they are fully documented in the F# language specification
Abstract computations
Handling of effects
async
1:
2:
3:
4:
5:
6:
7:
8:
9:
open System
let sleepWorkflow = async {
printfn "Starting sleep workflow at %O " DateTime . Now . TimeOfDay
do! Async . Sleep 2000
printfn "Finished sleep workflow at %O " DateTime . Now . TimeOfDay
}
Async . RunSynchronously sleepWorkflow
mbrace
1:
2:
3:
4:
5:
let job =
cloud {
return sprintf
"run in the cloud on worker '%s' " Environment . MachineName }
|> runtime . CreateProcess
Maybe problems
Slow
Hard to debug
Operator overuse
Next
It doesn't matter what things are
the otter king in his human form
Thanks :D