add basics.u sample file and delete a bunch of old .u files

This commit is contained in:
Paul Chiusano 2018-09-25 17:21:47 -04:00
parent f2e2b9ed7f
commit 7d9deec69a
15 changed files with 73 additions and 720 deletions

View File

@ -374,6 +374,7 @@ renderTypeError env e src = AT.AnnotatedDocument . Seq.fromList $ case e of
'2' -> "nd"
'3' -> "rd"
_ -> "th"
renderTerm (ABT.Var' v) | Settings.demoHideVarNumber = fromString (Text.unpack $ Var.name v)
renderTerm e = let s = show e in -- todo: pretty print
if length s > maxTermDisplay
then fromString (take maxTermDisplay s <> "...")

View File

@ -1,277 +0,0 @@
identity : ∀ a . a -> a
identity a = a
const x y = x
and-then : ∀ a b c . (a -> b) -> (b -> c) -> a -> c
and-then f1 f2 x = f2 (f1 x)
(|>) : ∀ a b . a -> (a -> b) -> b
a |> f = f a
(<|) : ∀ a b . (a -> b) -> a -> b
f <| a = f a
flip : ∀ a b c . (a -> b -> c) -> b -> a -> c
flip f b a = f a b
first : ∀ a b . Pair a b -> a
first p = Pair.fold const p
rest : ∀ a b . Pair a b -> b
rest p = Pair.fold (x y -> y) p
1st = first
2nd = rest `and-then` first
3rd = rest `and-then` (rest `and-then` first)
4th = rest `and-then` (rest `and-then` (rest `and-then` first))
5th = rest `and-then` (rest `and-then` (rest `and-then` (rest `and-then` first)))
set-1st : ∀ a a2 b . a2 -> Pair a b -> Pair a2 b
set-1st new-1st p = Pair new-1st (rest p)
Order.compare : ∀ a . Order a -> a -> a -> Comparison
Order.compare o a1 a2 = Order.Key.compare (Order.key o a1) (Order.key o a2)
Order.equal : ∀ a . Order a -> a -> a -> Boolean
Order.equal o a a2 =
Comparison.fold False True False (Order.compare o a a2)
Order.tuple2 : ∀ a b . Order a -> Order b -> Order (a,b)
Order.tuple2 a b = Pair.Order a (Pair.Order b Unit.Order)
Order.tuple3 : ∀ a b c . Order a -> Order b -> Order c -> Order (a,b,c)
Order.tuple3 a b c = Pair.Order a (Pair.Order b (Pair.Order c Unit.Order))
Order.by-1st : ∀ a b . Order a -> Order (Pair a b)
Order.by-1st a = Pair.Order a Order.ignore
Order.by-2nd : ∀ a b c . Order b -> Order (Pair a (Pair b c))
Order.by-2nd b = Pair.Order Order.ignore (Pair.Order b Order.ignore)
Order.by-3rd : ∀ a b c d . Order c -> Order (Pair a (Pair b (Pair c d)))
Order.by-3rd c = Pair.Order Order.ignore (Pair.Order Order.ignore (Pair.Order c Order.ignore))
Vector.bind : ∀ a b . (a -> Vector b) -> Vector a -> Vector b
Vector.bind f v = Vector.fold-balanced Vector.concatenate Vector.empty (Vector.map f v)
Vector.pure = Vector.single
Vector.replicate : ∀ a . Number -> a -> Vector a
Vector.replicate n a = Vector.map (const a) (Vector.range 0 n)
Vector.fold-right : ∀ a b . (a -> b -> b) -> b -> Vector a -> b
Vector.fold-right f z vs = Vector.fold-left (flip f) z (Vector.reverse vs)
Vector.fold-balanced : ∀ a . (a -> a -> a) -> a -> Vector a -> a
Vector.fold-balanced plus zero vs = let rec
go plus zero vs =
if Vector.size vs <=_Number 2
then Vector.fold-left plus zero vs
else let p = Vector.halve vs
go plus zero (1st p) `plus` go plus zero (2nd p)
go plus zero vs
Optional.map : ∀ a b . (a -> b) -> Optional a -> Optional b
Optional.map f = Optional.fold None (f `and-then` Some)
Optional.bind : ∀ a b . (a -> Optional b) -> Optional a -> Optional b
Optional.bind f a = Optional.fold None f a
Optional.pure : ∀ a . a -> Optional a
Optional.pure = Some
Optional.get-or : ∀ a . a -> Optional a -> a
Optional.get-or a = Optional.fold a identity
Optional.somes : ∀ a . Vector (Optional a) -> Vector a
Optional.somes = Vector.bind (Optional.fold Vector.empty Vector.single)
Optional.map2 : ∀ a b c . (a -> b -> c) -> Optional a -> Optional b -> Optional c
Optional.map2 f a b = do Optional
a := a
b := b
pure (f a b)
Optional.lift-or : ∀ a . (a -> a -> a) -> Optional a -> Optional a -> Optional a
Optional.lift-or f = a1 a2 ->
a1 |> Optional.fold a2 (a1 -> Optional.fold None (a2 -> Some (f a1 a2)) a2)
Optional.fold' : ∀ a b . (Unit -> b) -> (a -> b) -> Optional a -> Unit -> b
Optional.fold' thunk f = Optional.fold thunk (a u -> f a)
Vector.fold-balanced1 : ∀ a . (a -> a -> a) -> Vector a -> Optional a
Vector.fold-balanced1 f v = Vector.fold-balanced (Optional.lift-or f) None (Vector.map Some v)
Vector.join : ∀ a . Vector (Vector a) -> Vector a
Vector.join = Vector.bind identity
Vector.filter : ∀ a . (a -> Boolean) -> Vector a -> Vector a
Vector.filter f = Vector.bind (a -> if f a then [a] else [])
Vector.all? : ∀ a . (a -> Boolean) -> Vector a -> Boolean
Vector.all? f vs = Vector.fold-balanced and True (Vector.map f vs)
Vector.sort-by : ∀ k a . Order k -> (a -> k) -> Vector a -> Vector a
Vector.sort-by ok f v =
Vector.sort-keyed <| Vector.map (a -> (Order.key ok (f a), a)) v
Vector.sort : ∀ a . Order a -> Vector a -> Vector a
Vector.sort o = Vector.sort-by o identity
Vector.last : ∀ a . Vector a -> Optional a
Vector.last v = Vector.at (Vector.size v - 1) v
Vector.1st : ∀ a . Vector a -> Optional a
Vector.1st = Vector.at 0
Vector.drop-right : ∀ a . Number -> Vector a -> Vector a
Vector.drop-right n v = Vector.take (Vector.size v - n) v
Vector.take-right : ∀ a . Number -> Vector a -> Vector a
Vector.take-right n v = Vector.drop (Vector.size v - n) v
Vector.dedup-adjacent : ∀ a . (a -> a -> Boolean) -> Vector a -> Vector a
Vector.dedup-adjacent eq v =
Vector.fold-balanced
(v1 v2 ->
if Optional.map2 eq (Vector.last v1) (Vector.1st v2) |> Optional.get-or False
then Vector.concatenate v1 (Vector.drop 1 v2)
else Vector.concatenate v1 v2)
[]
(Vector.map Vector.pure v)
Vector.histogram : ∀ a . Order a -> Vector a -> Vector (a, Number)
Vector.histogram o v = let
merge-bin b1 b2 = (1st b1, 2nd b1 + 2nd b2)
combine bin1 bin2 =
Optional.map2 (p1 p2 -> if Order.equal o (1st p1) (1st p2)
then [merge-bin p1 p2]
else [p1, p2])
(Vector.last bin1) (Vector.1st bin2)
|> Optional.fold' (u -> Vector.concatenate bin1 bin2)
(p -> Vector.join [Vector.drop-right 1 bin1, p, Vector.drop 1 bin2])
<| Unit
Vector.fold-balanced combine [] (Vector.map (a -> Vector.pure (a, 1)) (Vector.sort o v))
Vector.ranked-histogram : ∀ a . Order a -> Vector a -> Vector (a, Number)
Vector.ranked-histogram o v =
Vector.histogram o v |> Vector.sort-by (Order.invert Number.Order) 2nd
Vector.sum : Vector Number -> Number
Vector.sum = Vector.fold-left (+) 0
Vector.dedup : ∀ a . Order a -> Vector a -> Vector a
Vector.dedup o v = Vector.dedup-adjacent (Order.equal o) (Vector.sort o v)
-- Remote.map : ∀ a b . (a -> b) -> Remote a -> Remote b
-- Remote.map f = Remote.bind (f `and-then` Remote.pure)
Remote.map2 : ∀ a b c . (a -> b -> c) -> Remote a -> Remote b -> Remote c
Remote.map2 f a b = do Remote
a := a
b := b
pure (f a b)
Remote.map2' : ∀ a b c . (a -> b -> Remote c) -> Remote a -> Remote b -> Remote c
Remote.map2' f a b = Remote.map2 f a b |> Remote.join
Remote.join : ∀ a . Remote (Remote a) -> Remote a
Remote.join = Remote.bind identity
Remote.unfold : ∀ s a . s -> (s -> Remote (Optional (a, s))) -> Remote (Vector a)
Remote.unfold s f = let rec
go s acc = do Remote
ht := f s
ht |> Optional.fold
(pure acc)
(ht -> go (2nd ht) (Vector.append (1st ht) acc))
go s Vector.empty
Remote.at' : ∀ a . Node -> Remote a -> Remote a
Remote.at' node r = do Remote { Remote.transfer node; r }
Remote.transfer : Node -> Remote Unit
Remote.transfer node = Remote.at node unit
Remote.replicate : ∀ a . Number -> Remote a -> Remote (Vector a)
Remote.replicate n r = Remote.sequence (Vector.replicate n r)
Remote.start : ∀ a . Duration -> Remote a -> Remote (Remote a)
Remote.start timeout r = do Remote
here := Remote.here
c := Remote.channel
result := Remote.receive-async c timeout
Remote.fork (Remote.at' here (r |> Remote.bind (Remote.send c)))
pure result
Remote.race : ∀ a . Duration -> Vector (Remote a) -> Remote a
Remote.race timeout rs = do Remote
here := Remote.here
c := Remote.channel
result := Remote.receive-async c timeout
Remote.traverse
(r -> Remote.fork <| (do Remote { a := r; Remote.transfer here; Remote.send c a }))
rs
result
-- Returns `None` if no response within the provided `timeout`,
-- which cannot exceed 500 seconds
Remote.timeout : ∀ a . Duration -> Remote a -> Remote (Optional a)
Remote.timeout timeout r =
Remote.race (Duration.seconds 501) [
Remote.map Some r,
do Remote { Remote.sleep timeout; pure None }
]
Remote.replicate! : ∀ a . Number -> Remote a -> Remote Unit
Remote.replicate! n a = let rec
go n =
if n <=_Number 0 then Remote.pure Unit
else Remote.bind (a -> go (n - 1)) a
go n
Remote.traverse : ∀ a b . (a -> Remote b) -> Vector a -> Remote (Vector b)
Remote.traverse f vs =
Vector.fold-balanced (Remote.map2 Vector.concatenate)
(Remote.pure Vector.empty)
(Vector.map (f `and-then` Remote.map Vector.single) vs)
Remote.sequence : ∀ a . Vector (Remote a) -> Remote (Vector a)
Remote.sequence vs =
Vector.fold-balanced (Remote.map2 Vector.concatenate)
(Remote.pure Vector.empty)
(Vector.map (Remote.map Vector.single) vs)
Remote.parallel-traverse : ∀ a b . Duration -> (a -> Remote b) -> Vector a -> Remote (Vector b)
Remote.parallel-traverse timeout f vs = do Remote
futures := Remote.traverse (f `and-then` Remote.start timeout) vs
Remote.sequence futures
-- Run several remote computations in parallel, returning once `n` equivalent
-- replies come back. Equivalence is based on result of `hash!`.
Remote.quorum : ∀ a b . Duration -> Number -> (a -> Remote b) -> Vector a -> Remote b
Remote.quorum timeout n = _ -- todo
Either.map : ∀ a b c . (b -> c) -> Either a b -> Either a c
Either.map f = Either.fold Left (f `and-then` Right)
Either.pure : ∀ a b . b -> Either a b
Either.pure = Right
Either.bind : ∀ a b c . (b -> Either a c) -> Either a b -> Either a c
Either.bind = Either.fold Left
Either.swap : ∀ a b . Either a b -> Either b a
Either.swap e = Either.fold Right Left e
Text.join : Vector Text -> Text
Text.join = Vector.fold-balanced Text.concatenate ""
Text.take-right : Number -> Text -> Text
Text.take-right n t = Text.drop (Text.length t - n) t
Text.ends-with : Text -> Text -> Boolean
Text.ends-with suffix overall =
Text.take-right (Text.length suffix) overall ==_Text suffix

72
unison-src/basics.u Normal file
View File

@ -0,0 +1,72 @@
-- Unison is a statically typed functional language
increment : Nat -> Nat -- signature is optional
increment n = n + 1
-- Lines starting with `>` are evaluated and printed on every file save.
> increment 99
replicate : Nat -> a -> [a]
replicate n a = to-sequence (take n (constant a))
-- this is nice for quick testing!
> replicate 3 "bye"
-- can ask Unison for the type of any expression just by adding `?` to the end of it
-- > (replicate 4)?
-- here's a more interesting example, mergesort -
-- First we define the merge function, it merges two sorted lists
merge : (a -> a -> Boolean) -> [a] -> [a] -> [a]
merge lte a b =
use Sequence ++
use Optional None Some
go acc a b = case at 0 a of
None -> acc ++ b
Some hd1 -> case at 0 b of
None -> acc ++ a
Some hd2 ->
if hd1 `lte` hd2 then go (acc `snoc` hd1) (drop 1 a) b
else go (acc `snoc` hd2) a (drop 1 b)
go [] a b
-- let's make sure it works
> merge (<) [1,3,4,99,504,799] [0,19,22,23]
-- looks good, now let's write mergesort
sort : (a -> a -> Boolean) -> [a] -> [a]
sort lte a =
if Sequence.size a < 2 then a
else
l = sort lte (take (size a / 2) a)
r = sort lte (drop (size a / 2) a)
merge lte l r
-- let's make sure it works
> sort (<) [3,2,1,1,2,3,9182,1,2,34,1,80]
> sort (<) ["Dave", "Carol", "Eve", "Alice", "Bob", "Francis", "Hal", "Illy", "Joanna", "Greg", "Karen"]
-- SHIP IT!! 🚢
-- If you make a mistake, we try to have nice friendly error messages, not:
-- 🤖 ERROR DETECTED ⚡️ BEEP BOOP ⚡️ PLS RESUBMIT PROGRAM TO MAINFRAME
-- a few examples of failing programs -
--err1 =
-- a = "3"
-- sort (<) [1,2,a]
-- err1a = sort (<) "not a list"
--err2 : x -> y -> x
--err2 thing1 thing2 =
-- if true then thing1
-- else thing2

View File

@ -1,29 +0,0 @@
-- a comment
{- {-
a multi-line nested comment
-} still a comment
-}
type Optional a = None | Some a
Optional.isEmpty : ∀ a . Optional a -> Boolean
Optional.isEmpty o = case o of
Optional.None -> true
Optional.Some hi@_ -> false
(|>) : forall a b . a -> (a -> b) -> b
a |> f = f a
let
foo : Nat -> Nat
foo x = case if x >_Nat 1 then x +_Nat 1 else 0
x = [1.,2.5]
"let case if"
|> Text.size
|> Stream.from-int
|> Stream.take 10
|> Stream.fold-left -0 (+_Int)
|> Stream.fold-left-0 (+_Int)
|> Optional.Some
+1.0

View File

@ -1,11 +0,0 @@
do Remote
root := Remote.spawn;
Remote.transfer root;
ind := DIndex.empty;
nodes := Remote.replicate 10 Remote.spawn;
Remote.traverse (node -> Remote.at' node (DIndex.join ind)) nodes;
DIndex.insert "It's..." "ALIIIVE!!!!" ind;
-- Remote.parallel-traverse DIndex.Timeout (k -> DIndex.insert k k ind) (Vector.range 0 5);
r := DIndex.lookup "It's..." ind;
pure (Debug.watch "result" r);;

View File

@ -1,88 +0,0 @@
-- A distributed index, using Highest Random Weight (HRW) hashing
-- to pick which nodes are responsible for which keys. See:
-- https://en.wikipedia.org/wiki/Rendezvous_hashing
DIndex.Replication-Factor = 1
DIndex.Timeout = Duration.seconds 10
DIndex.Max-Timeout = Duration.seconds 500
alias DIndex k v = Index Node (Index k v)
DIndex.empty : ∀ k v . Remote (DIndex k v)
DIndex.empty = Index.empty
-- Pick the nodes responsible for a key, using HRW hashing
DIndex.nodesForKey : ∀ k v . k -> DIndex k v -> Remote (Vector Node)
DIndex.nodesForKey k ind = do Remote
nodes := Index.keys ind
hashes := Remote.traverse (node -> hash! (node, k)) nodes
(nodes `Vector.zip` hashes)
|> Vector.sort-by Hash.Order 2nd
|> Vector.take DIndex.Replication-Factor
|> Vector.map 1st
|> pure
DIndex.lookup : ∀ k v . k -> DIndex k v -> Remote (Optional v)
DIndex.lookup k ind = do Remote
nodes := DIndex.nodesForKey k ind
localLookup = node -> do Remote
nind := Index.lookup node ind
-- on slim chance that a Node is removed from the cluster just before
-- we do the lookup, it gets treated like a timeout
Optional.fold (Remote.map (const None) (Remote.sleep DIndex.Timeout))
(Index.lookup k)
nind
-- todo: use Remote.quorum here
Remote.race DIndex.Timeout <| Vector.map localLookup nodes
DIndex.insert : ∀ k v . k -> v -> DIndex k v -> Remote Unit
DIndex.insert k v ind = do Remote
nodes := DIndex.nodesForKey k ind
localInsert = node -> do Remote
nind := Index.lookup node ind
Optional.fold (Remote.map (const Unit) (Remote.sleep DIndex.Timeout))
(Index.insert k v)
nind
Remote.race DIndex.Timeout <| Vector.map localInsert nodes
DIndex.join : ∀ k v . DIndex k v -> Remote Unit
DIndex.join ind = do Remote
here := Remote.here
localInd := Index.empty
Index.insert here localInd ind
DIndex.indicesForKey : ∀ k v . k -> DIndex k v -> Remote (Vector (Index k v))
DIndex.indicesForKey k ind = do Remote
nodes := DIndex.nodesForKey k ind
indices := Remote.traverse (node -> Index.lookup node ind) nodes
pure (Optional.somes indices)
DIndex.rebalance : ∀ k v . k -> DIndex k v -> Remote Unit
DIndex.rebalance k ind = do Remote
indices := DIndex.indicesForKey k ind
t = DIndex.Timeout
results := Remote.parallel-traverse DIndex.Max-Timeout (Index.lookup k `and-then` Remote.timeout t) indices
resultsHashes := Remote.traverse hash! results
uh := hash! None
hd = uh `Optional.get-or` Vector.at 0 resultsHashes
eq = h1 h2 -> Hash.erase h1 ==_Hash Hash.erase h2
if Vector.all? (eq hd) resultsHashes
-- all results matched, we're good
then pure Unit
-- not all results matched, reinsert
else do Remote
ov := DIndex.lookup k ind
Optional.fold (pure Unit)
(v -> DIndex.insert k v ind)
ov
DIndex.leave : ∀ k v . Node -> DIndex k v -> Remote Unit
DIndex.leave node ind = do Remote
local-ind := Index.lookup node ind
Index.delete node ind
Optional.fold
(pure Unit)
(local-ind -> do Remote {
keys := Index.keys local-ind;
Remote.fork <| Remote.traverse (k -> DIndex.rebalance k ind) keys })
local-ind

View File

@ -1,126 +0,0 @@
Index.empty : ∀ k v . Remote (Index k v)
Index.empty = Remote.map Index.empty# Remote.here
Index.keys : ∀ k v . Index k v -> Remote (Vector k)
Index.keys = Index.from-unsafe Index.keys#
Index.1st-key : ∀ k v . Index k v -> Remote (Optional k)
Index.1st-key = Index.from-unsafe Index.1st-key#
Index.increment : ∀ k v . k -> Index k v -> Remote (Optional k)
Index.increment k = Index.from-unsafe (Index.increment# k)
Index.lookup : ∀ k v . k -> Index k v -> Remote (Optional v)
Index.lookup k = Index.from-unsafe (Index.lookup# k)
Index.lookup-or : ∀ k v . v -> k -> Index k v -> Remote v
Index.lookup-or v k ind =
Remote.map (Optional.get-or v) (Index.lookup k ind)
Index.delete : ∀ k v . k -> Index k v -> Remote Unit
Index.delete k = Index.from-unsafe (Index.delete# k)
Index.insert : ∀ k v . k -> v -> Index k v -> Remote Unit
Index.insert k v = Index.from-unsafe (Index.insert# k v)
Index.inserts : ∀ k v . Vector (k,v) -> Index k v -> Remote Unit
Index.inserts vs ind = Remote.map (const Unit) <|
Remote.traverse (kv -> Index.insert (1st kv) (2nd kv) ind) vs
Index.from-unsafe : ∀ k v r . (Text -> r) -> Index k v -> Remote r
Index.from-unsafe f ind = let
p = Index.representation# ind
Remote.map f (Remote.at (1st p) (2nd p))
alias IndexedTraversal k v =
( Remote (Optional k) -- first key
, k -> Remote (Optional v) -- lookup the value for a key
, k -> Remote (Optional k)) -- increment a key
IndexedTraversal.1st-key : ∀ k v . IndexedTraversal k v -> Remote (Optional k)
IndexedTraversal.1st-key t = 1st t
IndexedTraversal.lookup : ∀ k v . k -> IndexedTraversal k v -> Remote (Optional v)
IndexedTraversal.lookup k t = 2nd t k
-- | Returns the smallest key in the traversal which is > the provided key.
IndexedTraversal.increment : ∀ k v . k -> IndexedTraversal k v -> Remote (Optional k)
IndexedTraversal.increment k t = 3rd t k
-- | Returns the smallest key in the traversal which is >= the provided key.
IndexedTraversal.ceiling : ∀ k v . k -> IndexedTraversal k v -> Remote (Optional k)
IndexedTraversal.ceiling k t =
IndexedTraversal.lookup k t |> Remote.bind (
Optional.fold (IndexedTraversal.increment k t) (const (pure <| Some k))
)
-- | Returns the smallest key existing in both traversals which is >= the provided key
IndexedTraversal.ceiling-both : ∀ k v . k -> IndexedTraversal k v -> IndexedTraversal k v -> Remote (Optional k)
IndexedTraversal.ceiling-both k t1 t2 =
IndexedTraversal.ceiling k t1 |>
Remote.bind (Optional.fold (Remote.pure None) (k -> IndexedTraversal.ceiling k t2))
Index.traversal : ∀ k v . Index k v -> IndexedTraversal (k, Hash k) v
Index.traversal ind = let
add-hash = Optional.map (k -> (k, hash# k))
( Index.1st-key ind |> Remote.map add-hash
, k -> Index.lookup (1st k) ind
, k -> Index.increment (1st k) ind |> Remote.map add-hash
)
IndexedTraversal.empty : ∀ k v . IndexedTraversal k v
IndexedTraversal.empty =
(Remote.pure None, const (Remote.pure None), const (Remote.pure None))
IndexedTraversal.intersect : ∀ k v . Order k
-> IndexedTraversal k v
-> IndexedTraversal k v
-> IndexedTraversal k v
IndexedTraversal.intersect o t1 t2 = let rec
align-key k1 k2 = Optional.get-or (Remote.pure None) <| Optional.map2
(k1 k2 -> Order.compare o k1 k2 |> Comparison.fold
-- k1 < k2
(IndexedTraversal.ceiling k2 t1 |> Remote.bind (k1 -> align-key k1 (Some k2)))
-- k1 == k2
(Remote.pure (Some k1))
-- k1 > k2
(IndexedTraversal.ceiling k1 t2 |> Remote.bind (k2 -> align-key (Some k1) k2))
)
k1 k2
1st-key = Remote.map2' align-key (1st t1) (1st t2)
lookup k = 2nd t1 k |> Remote.bind (Optional.fold (Remote.pure None) (a -> 2nd t2 k))
increment k = Remote.map2' align-key (3rd t1 k) (3rd t2 k)
(1st-key, lookup, increment)
IndexedTraversal.1st-entry : ∀ k v . IndexedTraversal k v -> Remote (Optional (k, v))
IndexedTraversal.1st-entry t = IndexedTraversal.entry-at (1st t) t
IndexedTraversal.entry-at : ∀ k v .
Remote (Optional k) -> IndexedTraversal k v -> Remote (Optional (k, v))
IndexedTraversal.entry-at k t = do Remote
k := k
v := Optional.fold (pure None) (2nd t) k
pure (Optional.map2 (k v -> (k,v)) k v)
IndexedTraversal.take : ∀ k v . Number -> IndexedTraversal k v -> Remote (Vector (k,v))
IndexedTraversal.take n t =
Remote.unfold (t, n) (tn -> let {
t = 1st tn;
n = 2nd tn;
step e = (e, (set-1st (IndexedTraversal.increment (1st e) t) t, n - 1));
if n <=_Number 0 then Remote.pure None
else IndexedTraversal.1st-entry t |> Remote.map (Optional.map step)
})
IndexedTraversal.take-keys : ∀ k v . Number -> IndexedTraversal k v -> Remote (Vector k)
IndexedTraversal.take-keys n t = IndexedTraversal.take n t |> Remote.map (Vector.map 1st)
Http.get-url : Text -> Remote (Either Text Text)
Http.get-url url = Remote.map Http.get-url# (Remote.pure url)
hash! : ∀ a . a -> Remote (Hash a)
hash! a = Remote.map hash# (Remote.pure a)

View File

@ -1,5 +0,0 @@
do Remote
Remote.fork <| Remote.sleep (Duration.seconds 10);
Remote.fork <| Remote.sleep (Duration.seconds 10);
pure 23;;

View File

@ -1,4 +0,0 @@
-- run from unison root directory
-- curl -H "Content-Type: text/plain; charset=UTF-8" --data-binary @node/tests/html.u http://localhost:8081/compute/dummynode909
Http.get-url "http://unisonweb.org"

View File

@ -1,15 +0,0 @@
-- run from unison root directory
-- curl -H "Content-Type: text/plain; charset=UTF-8" --data-binary @node/tests/index.u http://localhost:8081/compute/dummynode909
do Remote
n1 := Remote.spawn;
n2 := Remote.spawn;
ind := do Remote
Remote.transfer n1;
ind := Index.empty;
Index.insert "Alice" "Jones" ind;
Index.insert "Bob" "Smith" ind;
pure ind;;
;
Remote.transfer n2;
Index.lookup "Alice" ind;;

View File

@ -1,13 +0,0 @@
do Remote
n := Remote.spawn;
Remote.transfer n;
ind1 := Index.empty;
ind2 := Index.empty;
Index.inserts [(1,"a"), (2,"b"), (3,"b"), (9,"c"), (11,"f")] ind1;
t1 = Index.traversal ind1;
Index.inserts [(9,"c"), (2,"b"), (3,"b"), (7,"d")] ind2;
t2 = Index.traversal ind2;
t3 = IndexedTraversal.intersect (Order.by-2nd Hash.Order) t1 t2;
vs := IndexedTraversal.take 10 t3;
pure (Debug.watch "result" vs);;

View File

@ -1,17 +0,0 @@
-- run from unison root directory
-- curl -H "Content-Type: text/plain; charset=UTF-8" --data-binary @unison-src/pingpong.u http://localhost:8081/compute/root
do Remote
n1 := Remote.spawn;
n2 := Remote.spawn;
let rec
ping i = do Remote
i := Remote.at n2 (i + 1);
if (i >=_Number 5) (pure i) (pong i);;
;
pong i = do Remote
i := Remote.at n1 (i + 1);
ping i;;
;
ping 0;;
;;

View File

@ -1,6 +0,0 @@
do Remote
r := Remote.race (Duration.seconds 15) [
do Remote pure (Debug.watch "race.winner1" 1),
do Remote Remote.sleep (Duration.seconds 10); pure (Debug.watch "race.winner2" 2)
]
pure <| Debug.watch "result" r

View File

@ -1,8 +0,0 @@
do Remote
c := Remote.channel;
r := Remote.receive-async c (Duration.seconds 5);
Remote.fork (Remote.send c (Debug.watch "sent" 42));
-- Remote.send c 42; -- (Debug.watch "sent" 42);
r;;

View File

@ -1,121 +0,0 @@
let
alias DIndex k v = Index Node (Index k v)
alias Set v = Index v Unit
-- Maps keywords to set of page content hashes with that keyword
alias SearchIndex = DIndex Text (Set (Hash Text))
-- Maps page hash to canonical Url for that hash
alias CanonicalUrls = DIndex (Hash Text) Text
-- Maps page hash to a short, plain text exerpt from that page
alias Excerpts = DIndex (Hash Text) Text
-- Using the search index, returns the list of page hashes (up to limit)
-- whose content contains all the keywords of the query
search : Number -> Vector Text -> SearchIndex
-> Remote (Vector (Hash Text))
search limit query ind = do Remote
url-sets := Remote.traverse (k -> DIndex.lookup k ind) query
url-sets = Vector.map Index.traversal (Optional.somes url-sets)
merge = IndexedTraversal.intersect (Order.by-2nd Hash.Order)
urls = Optional.get-or IndexedTraversal.empty <| Vector.fold-balanced1 merge url-sets
urls := IndexedTraversal.take-keys limit urls
pure (Vector.map 1st urls)
-- Plain-text formating of a set of results
format-results : Vector (Hash Text) -> CanonicalUrls -> Excerpts -> Remote Text
format-results hs urls excerpts = do Remote
urls := Remote.map Optional.somes <| Remote.traverse (h -> DIndex.lookup h urls) hs
excerpts := Remote.map Optional.somes <| Remote.traverse (h -> DIndex.lookup h excerpts) hs
fmt = p -> Text.join [1st p, Text.newline, 2nd p, Text.newline, "***", Text.newline]
pure <| Text.join (Vector.map fmt (urls `Vector.zip` excerpts))
trim-to-host : Text -> Text
trim-to-host url = Optional.get-or url <| do Optional
host := Uri.parse-authority url
scheme := Uri.parse-scheme url
pure (Text.concatenate scheme ("//" `Text.concatenate` host))
-- | Convert url (possibly relative to parent) to an absolute url
resolve-url : Text -> Text -> Text
resolve-url parent child =
if Text.take 1 child ==_Text "/" then
Text.concatenate (trim-to-host parent) child
else if (Text.take 5 child ==_Text "http:") `or` (Text.take 6 child ==_Text "https:") then
child
else Text.join [parent, if Text.ends-with "/" parent then "" else "/", child]
crawl : Number -> SearchIndex -> CanonicalUrls -> Excerpts -> Text -> Remote Unit
crawl depth ind visited excerpts url = let rec
insert url keyword = do Remote
url-set := DIndex.lookup keyword ind
Optional.fold
(do Remote {
url-set := Index.empty;
DIndex.insert keyword url-set ind;
insert url keyword
})
(Index.insert url Unit)
url-set
go depth url =
if depth <=_Number 0 then Remote.pure Unit
else do Remote
page := Remote.map (Debug.log "indexing url" url) (Http.get-url url)
page = Either.fold (err -> Debug.log "error fetching" (url, err) "") identity page
page-hash := hash! page
h := DIndex.lookup page-hash visited
Optional.fold
(do Remote {
page-text = Html.plain-text page;
keywords = Text.words page-text
|> Vector.map Text.lowercase
|> Vector.ranked-histogram Text.Order;
summary = Vector.take 100 keywords; -- hacky filter
keywords = summary;
keywords = Vector.map 1st keywords;
links = Html.get-links page;
links = Vector.map (Html.get-href `and-then` resolve-url url) links;
-- insert all keywords for the page into the map
Remote.traverse (insert page-hash) keywords;
-- mark page as visited
excerpt = Text.take 400 page-text `Text.concatenate` "...";
DIndex.insert page-hash excerpt excerpts;
Debug.log "finished indexing" url <| DIndex.insert page-hash url visited;
-- recurse
Remote.traverse (go (depth - 1)) links;
pure Unit
})
(x -> Remote.pure (Debug.log "already visited" url Unit))
h
go depth url
do Remote
n := Remote.spawn
Remote.transfer n
-- Build DIndex for index state and for crawler state
ind := DIndex.empty
visited := DIndex.empty
excerpts := DIndex.empty
ind-nodes := Remote.replicate 3 Remote.spawn
visited-nodes := Remote.replicate 3 Remote.spawn
excerpts-nodes := Remote.replicate 3 Remote.spawn
Remote.traverse (n -> Remote.at' n (DIndex.join ind)) ind-nodes
Remote.traverse (n -> Remote.at' n (DIndex.join visited)) visited-nodes
Remote.traverse (n -> Remote.at' n (DIndex.join excerpts)) excerpts-nodes
-- Kick off multiple crawlers
Remote.fork <| crawl 5 ind visited excerpts "http://unisonweb.org/design"
Remote.fork <| crawl 5 ind visited excerpts "http://www.cnn.com"
Remote.fork <| crawl 5 ind visited excerpts "http://lambda-the-ultimate.org/"
-- Wait a while for crawlers to index a bunch of pages, then do query
u = Debug.watch "waiting 2 minutes for indexing before issuing queries..." Unit
Remote.sleep (Duration.seconds 120)
u = Debug.watch "done waiting for indexing, getting results" Unit
results := search 10 ["design", "unison", "programming"] ind
results := format-results results visited excerpts
pure <| Debug.log results Unit results
-- pure <| Debug.watch "results" results