Skip to content

Instantly share code, notes, and snippets.

@thinkbeforecoding
Last active August 29, 2015 13:57
Show Gist options
  • Save thinkbeforecoding/9512576 to your computer and use it in GitHub Desktop.
Save thinkbeforecoding/9512576 to your computer and use it in GitHub Desktop.
Fun with Akka.net
#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)
@thinkbeforecoding
Copy link
Author

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment