Last active
August 29, 2015 13:57
-
-
Save thinkbeforecoding/9512576 to your computer and use it in GitHub Desktop.
Fun with Akka.net
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#r @"C:\Development\GitHub\Pigeon\src\Pigeon\bin\Release\Akka.dll" | |
#r @"C:\Development\GitHub\Pigeon\src\Pigeon.FSharp\bin\Release\Akka.FSharp.dll" | |
open Akka.FSharp | |
open Akka.Actor | |
type IO<'msg> = | Input | |
type Cont<'m,'v> = | |
| Func of ('m -> Cont<'m,'v>) | |
| Return of 'v | |
type ActorBuilder() = | |
member this.Bind(m : IO<'msg>, f :'msg -> _) = | |
Func (fun m -> f m) | |
member this.Bind(x : Cont<'m,'a>, f :'a -> Cont<'m,'b>) : Cont<'m,'b> = | |
match x with | |
| Func fx -> Func(fun m -> this.Bind(fx m, f)) | |
| Return v -> f v | |
member this.ReturnFrom(x) = x | |
member this.Return x = Return x | |
member this.Zero() = Return () | |
member this.TryWith(f:Cont<'m,'a>,c: exn -> Cont<'m,'a>): Cont<'m,'a> = | |
Func(fun m -> | |
match f with | |
| Func fn -> | |
try | |
true, fn m | |
with | |
| ex -> false, c ex | |
| _ -> false, f | |
|> function | |
| true,r -> this.TryWith(r, c) | |
| false,r -> r | |
) | |
member this.Delay(f: unit -> Cont<_,_>) = | |
f() | |
member this.Combine(f,g) = | |
match f with | |
| Func fx -> Func(fun m -> this.Combine(fx m, g)) | |
| Return v -> g | |
let actor = ActorBuilder() | |
type FunActor<'m,'v>(actor: IO<'m> -> Cont<'m,'v>) = | |
inherit Actor() | |
let mutable state = actor Input | |
override x.OnReceive(msg) = | |
let message = msg :?> 'm | |
match state with | |
| Func f -> state <- f message | |
| Return v -> x.PostStop() | |
module Actor = | |
let system name = | |
ActorSystem.Create(name) | |
let spawn (system:ActorSystem) (f: (IO<'m> -> Cont<'m,'v>)) = | |
system.ActorOf(Props(Deploy.Local, typeof<FunActor<'m,'v>>, [f])) | |
let system = Actor.system "Actors" | |
type Message = | |
| Inc of int | |
| Dec of int | |
| Start of int | |
| Stop | |
let a = | |
Actor.spawn system | |
<| fun recv -> | |
let rec loop s = | |
actor { | |
let! msg = recv | |
printfn "%d" s | |
match msg with | |
| Inc n -> | |
return! loop (s + n) | |
| Dec n -> | |
return! loop (s - n) | |
| Stop -> return! stop () | |
| _ -> return! loop s | |
} | |
and stop () = actor { | |
let! _ = recv | |
printfn "I'm stopped" | |
return! stop() | |
} | |
let rec handleFirstMessages() = | |
actor { | |
let! m = recv | |
match m with | |
| Start n -> | |
printfn "We can now start with %d" n | |
return n | |
| _ -> | |
printfn "Skip while its not Start (%A)!" m | |
return! handleFirstMessages() | |
} | |
let trySomething() = | |
actor { | |
try | |
let! m = recv | |
printfn "in try %A" m | |
match m with | |
| Stop -> failwith "Stop should not follow start" | |
| _ -> printfn "skip" | |
printfn "Should not appear" | |
let! m = recv | |
printfn "Should not appear" | |
with | |
| _ -> printfn "catched" | |
} | |
actor { | |
let! v = handleFirstMessages() | |
printfn "value from fn %d" v | |
do! trySomething() | |
return! loop v | |
} | |
a <! Stop | |
a <! Inc 1 | |
a <! Start 7 | |
a <! Stop | |
[0..10] |> List.iter(fun _ -> a <! Inc 2) | |
[0..10] |> List.iter (fun _ -> a <! Dec 1) | |
a <! Stop | |
[0..10] |> List.iter (fun _ -> a <! Inc 1) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This version skips messages while it's not Start, takes the value in start as a seed for computation
It then get the next message, if it's Stop, it'll raise an exception that is catched, else, it skips the next message
It then enters a computation loop using the seed, which increments or decrments the accumulator. until stop is received in which case it just prints "I'm stopped" and and forget messages...