unison/unison-src/tests/hang.u

90 lines
2.5 KiB
Plaintext

use Universal == <
structural type Future a = Future ('{Remote} a)
-- A simple distributed computation ability
structural 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} Future a
structural type Node = Node Nat -- more realistic would be perhaps a (Hostname, PublicKey) pair
force : Future a ->{Remote} a
force = cases Future.Future r -> !r
-- 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 =
use Future Future
step nid = cases
{a} -> a
{Remote.fork t -> k} -> handle k (Future 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)
Remote.forkAt : Node -> '{Remote} a ->{Remote} (Future a)
Remote.forkAt node r = Remote.fork '(Remote.at node r)
use Optional None Some
use Monoid Monoid
use List ++
List.map : (a ->{e} b) -> [a] ->{e} [b]
List.map f as =
go f acc as i = match List.at i as with
None -> acc
Some a -> go f (snoc acc (f a)) as (i + 1)
go f [] as 0
merge : (a -> a -> Boolean) -> [a] -> [a] -> [a]
merge lte a b =
use List at
go acc a b = match at 0 a with
None -> acc ++ b
Some hd1 -> match at 0 b with
None -> acc ++ a
Some hd2 ->
if lte hd1 hd2 then go (snoc acc hd1) (drop 1 a) b
else go (snoc acc hd2) a (drop 1 b)
go [] a b
dsort2 : (a -> a -> Boolean) -> [a] ->{Remote} [a]
dsort2 lte as =
if size as < 2 then as
else match halve as with
None -> as
Some (left, right) ->
use Remote forkAt spawn
l = forkAt spawn '(dsort2 lte left)
r = forkAt spawn '(dsort2 lte right)
merge lte (force l) (force r)
isEmpty : [a] -> Boolean
isEmpty a = size a == 0
halve : [a] -> Optional ([a], [a])
halve as =
if isEmpty as then None
else Some (take (size as / 2) as, drop (size as / 2) as)
Node.increment : Node -> Node
Node.increment n =
use Node Node -- the constructor
match n with Node n -> Node (n + 1)
> Remote.runLocal '(dsort2 (<) [3,2,1,1,2,3,9182,1,2,34,1,23])