-- A simple distributed computation ability ability Remote where -- Spawn a new node spawn : {Remote} Node -- Sequentially evaluate the given thunk on another node -- then return to the current node when it completes at : n -> '{Remote} a -> {Remote} a -- Start a computation running, returning an `r` that can be forced to -- await the result of the computation fork : '{Remote} a -> {Remote} ('{Remote} a) type Node = Node Nat -- more realistic would be perhaps a (Hostname, PublicKey) pair replicate : Nat -> a -> [a] replicate n a = toSequence (take n (constant a)) -- here's a simple usage of it - this ships the program `replicate n a` -- to another node and evaluates it there before returning to the current node ex1 : Nat -> a -> {Remote} [a] ex1 n a = node = Remote.spawn -- conjures up a new node! Remote.at node '(replicate n a) -- and transports a computation to it! -- Let's test out this beast! do we need to deploy our code to some EC2 instances?? -- Gak, no not yet, we just want to test locally, let's write a handler -- for the `Remote` ability that simulates everything locally! Remote.runLocal : '{Remote} a -> a Remote.runLocal r = step nid r = case r of {a} -> a {Remote.fork t -> k} -> handle (step nid) in k t {Remote.spawn -> k} -> handle (step (Node.increment nid)) in k nid {Remote.at _ t -> k} -> handle (step nid) in k !t handle (step (Node.Node 0)) in !r -- Q: where do these nodes come from? that depends on the handler - -- you might have a handler like this, or a handler backed by an autoscaling EC2 pool... -- easy peasy, let's give it a go... > Remote.runLocal '(ex1 10 "hi") -- let's do some stuff in parallel on multiple nodes ex2 n = -- spin up two remote computations on fresh nodes, in parallel, then combine their results r1 = Remote.forkAt Remote.spawn '(replicate n "hi") -- returns a 'future' r2 = Remote.forkAt Remote.spawn '(replicate n "there") !r1 ++ !r2 > Remote.runLocal '(ex2 5) -- little helper functions used above Remote.forkAt : Node -> '{Remote} a -> {Remote} ('{Remote} a) Remote.forkAt node r = Remote.fork '(Remote.at node r) Node.increment : Node -> Node Node.increment n = use Node.Node -- the constructor case n of Node n -> Node (n + 1)