mirror of
https://github.com/unisonweb/unison.git
synced 2024-09-11 10:35:57 +03:00
68 lines
2.2 KiB
Plaintext
68 lines
2.2 KiB
Plaintext
|
|
-- 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 = cases
|
|
{a} -> a
|
|
{Remote.fork t -> k} -> handle k t with step nid
|
|
{Remote.spawn -> k} -> handle k nid with step (Node.increment nid)
|
|
{Remote.at _ t -> k} -> handle k !t with step nid
|
|
handle !r with step (Node.Node 0)
|
|
|
|
-- 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
|
|
match n with Node n -> Node (n + 1)
|