Mirage Lambda allows to describe functions using a monomorphic typed lambda calculus with well-typed host primitives (for instance calls to the MirageOS APIs). A client can use the eDSL to describe the function to execute remotely. The Mirage Lambda API provides ways to parse, print, type, untype and to evaluate these terms. These functions can be used by both the client and the servers to ship code to be run on remotely.
Mirage Lambda can be installed with opam
:
opam install mirage-lambda
If you don't use opam
consult the opam
file for build
instructions.
The documentation and API reference is automatically generated by from
the source interfaces. It can be consulted online or via
odig doc cmdliner
.
The factorial can be defined as a ('a, int -> int) Lambda.Expr.t
value.
The 'a
is the of the environment, int -> int
is the type of the expression:
open Lambda
let fact =
let open Expr in
let main =
let_rec Type.("x", int ** int) Type.int (fun ~context ~return ~continue ->
let acc = fst context in
let n = snd context in
(if_ (n = int 0)
(return acc)
(continue (pair (acc * n) (n - int 1))))
) in
lambda ("x", Type.int) (main $ (pair (int 1) (var Var.o)))
To ship the code and waiting for a server response:
let u = Expr.untype fact in (* Generate an AST *)
let s = Parsetree.to_string u in (* Pretty-print the AST *)
send s >>= receive
The lambda server, on the other-side will receive the code, type it, and evaluate it and send the response back:
receive () >>= fun s ->
let u = parse_exn s in (* Parse *)
let e = typ_exn u in (* Type *)
let v = eval e in (* Evaluate *)
send (string_of_value v)
The server can also defines a list of host function primitives that it can exposes to the clients:
let primitives = [
primitive "string_of_int" [Type.int] Type.string string_of_int
primitive "string_of_float" [Type.float] Type.string string_of_int
] in
...
(* Exposes the names [string_of_int] and [string_of_float] in the context. *)
let v = parse_exn ~primitives s in
...
To run the mirage-lambda demo app:
$ make block # this create an empty ./disk.img
$ docker run -it -v `pwd`/disk.img:/disk.img -p 1234:1234 samoht/mirage-lambda
This app will listen on port 1234
for incoming connections and use
./disk.img
as block-device storage backend.