Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compiler bug #34

Draft
wants to merge 12 commits into
base: master
Choose a base branch
from
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ jobs:
dfx start --background
dfx deploy --no-wallet
dfx canister call Calc test
dfx canister call Sort test
- name: Build docs
run: /home/runner/.cache/dfinity/versions/$DFX_VERSION/mo-doc
- name: Upload docs
Expand Down
3 changes: 3 additions & 0 deletions dfx.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
"canisters": {
"Calc": {
"main": "examples/calc/Main.mo"
},
"Sort": {
"main": "examples/sort/Main.mo"
}
},
"defaults": {
Expand Down
34 changes: 34 additions & 0 deletions examples/sort/Main.mo
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import Meta "../../src/data/Meta";
import Sort "Sort";

actor {
var sort = Sort.Sort();
let meta = Meta.Counter();
public query func test() : async () {
let r =
sort.eval(
#seq(#treeOfStream(#streamOfArray(
#array(
[
(#val(#num 04), meta.next()),
(#val(#num 16), meta.next()),
(#val(#num 02), meta.next()),
(#val(#num 07), meta.next()),
(#val(#num 11), meta.next()),
(#val(#num 09), meta.next()),
(#val(#num 06), meta.next()),

(#val(#num 23), meta.next()),
(#val(#num 08), meta.next()),
(#val(#num 13), meta.next()),
(#val(#num 06), meta.next()),
(#val(#num 14), meta.next()),
(#val(#num 17), meta.next()),
(#val(#num 16), meta.next()),
]
)))));

ignore sort.takeLog();

};
}
100 changes: 100 additions & 0 deletions examples/sort/Sort.mo
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import Engine "../../src/Engine";
import Seq "../../src/data/Sequence";
import Meta "../../src/data/Meta";
import R "mo:base/Result";
import L "mo:base/List";
import Text "mo:base/Text";
import Debug "mo:base/Debug";

/**
Incremental sorting example.
Uses adapton for representing stream thunks and caching them as data changes.
*/
module {

public type Name = Meta.Name;

public type Val = {
#unit;
#num : Nat;
#seq : Seq.Val<Val>;
};

public type Error = {
#typeMismatch;
#seq : Seq.Error<Val>;
};

public type Exp = {
#unit;
#num : Nat;
#seq : Seq.Exp<Val>;
};

public class Sort() {
/* -- cache implementation, via adapton package -- */
public var engine : Engine.Engine<Name, Val, Error, Exp> =
Engine.Engine<Name, Val, Error, Exp>(
{
nameEq=func (x:Name, y:Name) : Bool { x == y };
valEq=func (x:Val, y:Val) : Bool { x == y };
closureEq=func (x:Exp, y:Exp) : Bool { x == y };
errorEq=func (x:Error, y:Error) : Bool { x == y };
nameHash=Meta.Name.hash;
cyclicDependency=func (stack:L.List<Name>, name:Name) : Error {
Debug.print(debug_show {stack; name});
assert false; loop { }
}
},
true // logging
);
public var engineIsInit = false;

public var seq = Seq.Sequence<Val, Error, Exp>(
engine,
{
valMax = func(v1 : Val, v2 : Val) : R.Result<Val, Error> {
switch (v1, v2) {
case (#num n1, #num n2)
#ok(#num(if (n1 > n2) n1 else n2));
case _ #err(#typeMismatch);
}
};
getVal = func(v : Val) : ?Seq.Val<Val> =
switch v { case (#seq(s)) ?s; case _ null };
putVal = func(v : Seq.Val<Val>) : Val = #seq(v);
putExp = func(e : Seq.Exp<Val>) : Exp = #seq(e);
getExp = func(e : Exp) : ?Seq.Exp<Val> =
switch e { case (#seq(e)) ?e; case _ null };
putError = func(e : Seq.Error<Val>) : Error = #seq(e);
getError = func(e : Error) : ?Seq.Error<Val> =
switch e { case (#seq(e)) ?e; case _ null };
}
);

func evalRec(exp : Exp) : R.Result<Val, Error> {
switch exp {
case (#unit) #ok(#unit);
case (#num n) #ok(#num n);
case (#seq e) seq.eval(e);
}
};

public func eval(exp : Exp) : R.Result<Val, Error> {
if (not engineIsInit) {
engine.init({eval=evalRec});
engineIsInit := true
};
evalRec(exp)
};

public func takeLog() : Engine.Log<Name, Val, Error, Exp> {
let log = engine.takeLog();
debug { Debug.print (debug_show log) };
log
};

};

}

6 changes: 6 additions & 0 deletions src/Engine.mo
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@ module {
context.logOps.end(tag)
};

public func nest<X>(name : Name, body : () -> X) : X {
// to do -- enter nested namespace using name
body()
// to do -- resume original namespace
};

public func put(name:Name, val:Val) : R.Result<Name, G.PutError> {
logBegin();
let newRefNode : G.Ref<Name, Val, Error, Closure> = {
Expand Down
64 changes: 64 additions & 0 deletions src/data/Meta.mo
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import Engine "../Engine";

import H "mo:base/Hash";
import L "mo:base/List";
import R "mo:base/Result";
import P "mo:base/Prelude";
import Int "mo:base/Int";
import Debug "mo:base/Debug";
import Text "mo:base/Text";
import Nat "mo:base/Nat";
import Nat32 "mo:base/Nat32";

module {

/// Names as untyped symbol trees.
/// Names serve as locally-unique dynamic identifiers.
public type Name = {
#none;
#int : Int;
#nat : Nat;
#text : Text;
#bin : (Name, Name);
#tri : (Name, Name, Name);
#cons : (Name, [ Name ]);
#record : [(Name, Name)];
};

// Levels define [Cartesian trees](https://en.wikipedia.org/wiki/Cartesian_tree).
public type Level = Nat;

// Meta data within inductive components of incremental data structures.
public type Meta = {
name : Name;
level : Level;
};

public module Level {
public func ofNat(n : Nat) : Level {
Nat32.toNat(Nat32.bitcountLeadingZero(H.hash(n)))
}
};

public module Name {
public func hash (n : Name) : H.Hash {
switch n {
case (#none) Text.hash "none";
case (#text(t)) Text.hash t;
case _ Text.hash "?"; // to do
}
};
};

public class Counter() {
var counter : Nat = 0;
public func next () : Meta {
let level = Level.ofNat(counter);
let name = #nat counter;
let meta = {level; name};
counter += 1;
meta
};
};

}
13 changes: 13 additions & 0 deletions src/data/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Incremental data (structures)

Following ideas from earlier [(nominal) Adapton implementations and papers](http://adapton.org).

- [ ] Stacks -- as singly linked lists.
- [ ] Sequences -- as binary [Cartesian trees](https://en.wikipedia.org/wiki/Cartesian_tree).
- [ ] Maps -- as [binary tries](https://en.wikipedia.org/wiki/Trie).

Each structure and its algorithms use names in its inductive definition.

During change propagation, these names distinguish independent components
of each structure as it undergoes incremental change.

Loading