2 people like it.
Like the snippet!
Actors acting as Lambdas
The Untyped Lambda Calculus encoded as actors (F#'s MailboxProcessors)
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
|
// Useful type aliases
type Actor = MailboxProcessor<obj>
type Ident = string
type Cond = Actor
type Env = Actor
let (<!>) (actor : Actor) (msg : 'T) = actor.Post msg
// run forever - template
let start<'T> (work : 'T -> unit) : Actor =
MailboxProcessor<obj>.Start(fun mb ->
let rec loop () =
async {
let! msg = mb.Receive()
match msg with
| :? 'T as msg' -> work msg'
| _ -> () // oops... undefined behaviour
return! loop ()
}
loop () )
// Helper print expression
let printExp = start<obj>(fun value -> printfn "Print: %A" value)
// Enviroment encoding functions
let emptyEnv =
start<Cond * Ident>(fun _ -> ()(*oops... undefined behaviour*))
let buildEnv ident value env =
start<Cond * Ident>(fun (cond, ident') -> if ident = ident' then cond <!> value else env <!> (cond, ident'))
// Closures are also actors
let closure ident body env =
start<Cond * obj>(fun (cond, arg) -> let env' = buildEnv ident arg env in body <!> (cond, env'))
// Lambda Calculus expressions
let constExp value = start<Cond * Env>(fun (cond, _) -> cond <!> value)
let identExp ident = start<Cond * Env>(fun (cond, env) -> env <!> (cond, ident))
let lambdaExp ident body =
start<Cond * Env>(fun (cond, env) -> cond <!> closure ident body env)
let appExp exp argExp =
start<Cond * Env>(fun (cond, env) ->
let closureCond =
start<Cond>(fun closure ->
let argCond = start<obj>(fun value -> closure <!> (cond, value))
argExp <!> (argCond, env))
exp <!> (closureCond, env))
// Examples
let idExp = lambdaExp "x" (identExp "x")
let example = appExp idExp (constExp 42)
example <!> (printExp, emptyEnv) // Print: 42
let selfAppExp = lambdaExp "x" (appExp (identExp "x") (identExp "x"))
let omega = appExp selfAppExp selfAppExp
omega <!> (printExp, emptyEnv) // run forever
|
Multiple items
type MailboxProcessor<'Msg> =
interface IDisposable
new : body:(MailboxProcessor<'Msg> -> Async<unit>) * ?cancellationToken:CancellationToken -> MailboxProcessor<'Msg>
member Post : message:'Msg -> unit
member PostAndAsyncReply : buildMessage:(AsyncReplyChannel<'Reply> -> 'Msg) * ?timeout:int -> Async<'Reply>
member PostAndReply : buildMessage:(AsyncReplyChannel<'Reply> -> 'Msg) * ?timeout:int -> 'Reply
member PostAndTryAsyncReply : buildMessage:(AsyncReplyChannel<'Reply> -> 'Msg) * ?timeout:int -> Async<'Reply option>
member Receive : ?timeout:int -> Async<'Msg>
member Scan : scanner:('Msg -> Async<'T> option) * ?timeout:int -> Async<'T>
member Start : unit -> unit
member TryPostAndReply : buildMessage:(AsyncReplyChannel<'Reply> -> 'Msg) * ?timeout:int -> 'Reply option
...
Full name: Microsoft.FSharp.Control.MailboxProcessor<_>
--------------------
new : body:(MailboxProcessor<'Msg> -> Async<unit>) * ?cancellationToken:System.Threading.CancellationToken -> MailboxProcessor<'Msg>
type obj = System.Object
Full name: Microsoft.FSharp.Core.obj
type Ident = string
Full name: Script.Ident
Multiple items
val string : value:'T -> string
Full name: Microsoft.FSharp.Core.Operators.string
--------------------
type string = System.String
Full name: Microsoft.FSharp.Core.string
type Cond = Actor
Full name: Script.Cond
type Actor = MailboxProcessor<obj>
Full name: Script.Actor
type Env = Actor
Full name: Script.Env
val actor : Actor
val msg : 'T
member MailboxProcessor.Post : message:'Msg -> unit
val start : work:('T -> unit) -> Actor
Full name: Script.start
val work : ('T -> unit)
type unit = Unit
Full name: Microsoft.FSharp.Core.unit
val mb : MailboxProcessor<obj>
val loop : (unit -> Async<'a>)
val async : AsyncBuilder
Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.async
val msg : obj
member MailboxProcessor.Receive : ?timeout:int -> Async<'Msg>
val msg' : 'T
val printExp : Actor
Full name: Script.printExp
val value : obj
val printfn : format:Printf.TextWriterFormat<'T> -> 'T
Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printfn
val emptyEnv : Actor
Full name: Script.emptyEnv
val buildEnv : ident:Ident -> value:'a -> env:Actor -> Actor
Full name: Script.buildEnv
val ident : Ident
val value : 'a
val env : Actor
val cond : Cond
val ident' : Ident
val closure : ident:Ident -> body:Actor -> env:Actor -> Actor
Full name: Script.closure
val body : Actor
val arg : obj
val env' : Actor
val constExp : value:'a -> Actor
Full name: Script.constExp
val identExp : ident:'a -> Actor
Full name: Script.identExp
val ident : 'a
val env : Env
val lambdaExp : ident:Ident -> body:Actor -> Actor
Full name: Script.lambdaExp
val appExp : exp:Actor -> argExp:Actor -> Actor
Full name: Script.appExp
val exp : Actor
val argExp : Actor
val closureCond : Actor
val closure : Cond
val argCond : Actor
val idExp : Actor
Full name: Script.idExp
val example : Actor
Full name: Script.example
val selfAppExp : Actor
Full name: Script.selfAppExp
val omega : Actor
Full name: Script.omega
More information