/* This is an example in the Koka Language of the Garcia-Wachs algorithm */ module garcia-wachs public fun main() { test().print } //---------------------------------------------------- // Trees //---------------------------------------------------- public type tree { con Leaf(value :a) con Node(left :tree, right :tree) } fun show( t : tree ) : string { match(t) { Leaf(c) -> Core.show(c) Node(l,r) -> "Node(" + show(l) + "," + show(r) + ")" } } //---------------------------------------------------- // Non empty lists //---------------------------------------------------- public type list1 { Cons1( head : a, tail : list ) } fun map( xs, f ) { val Cons1(y,ys) = xs return Cons1(f(y), Core.map(ys,f)) } fun zip( xs :list1, ys :list1 ) : list1<(a,b)> { Cons1( (xs.head, ys.head), zip(xs.tail, ys.tail)) } //---------------------------------------------------- // Phase 1 //---------------------------------------------------- fun insert( after : list<(tree,int)>, t : (tree,int), before : list<(tree,int)> ) : div tree { match(before) { Nil -> extract( [], Cons1(t,after) ) Cons(x,xs) -> { if (x.snd < t.snd) then return insert( Cons(x,after), t, xs ) match(xs) { Nil -> extract( [], Cons1(x,Cons(t,after)) ) Cons(y,ys) -> extract( ys, Cons1(y,Cons(x,Cons(t,after))) ) } } } } fun extract( before : list<(tree,int)>, after : list1<(tree,int)> ) : div tree { val Cons1((t1,w1) as x, xs ) = after match(xs) { Nil -> t1 Cons((t2,w2) as y, ys) -> match(ys) { Nil -> insert( [], (Node(t1,t2), w1+w2), before ) Cons((_,w3),_zs) -> if (w1 <= w3) then insert(ys, (Node(t1,t2), w1+w2), before) else extract(Cons(x,before), Cons1(y,ys)) } } } fun balance( xs : list1<(tree,int)> ) : div tree { extract( [], xs ) } fun mark( depth :int, t :tree<(a,ref)> ) : > () { match(t) { Leaf((_,d)) -> d := depth Node(l,r) -> { mark(depth+1,l); mark(depth+1,r) } } } fun build( depth :int, xs :list1<(a,ref)> ) : ,div> (tree,list<(a,ref)>) { if (!xs.head.snd == depth) return (Leaf(xs.head.fst), xs.tail) l = build(depth+1, xs) match(l.snd) { Nil -> (l.fst, Nil) Cons(y,ys) -> { r = build(depth+1, Cons1(y,ys)) (Node(l.fst,r.fst), r.snd) } } } public fun test() { wlist = Cons1(('a',3), [('b',2),('c',1),('d',4),('e',5)]) tree = wlist.garciawachs() tree.show() } public fun garciawachs( xs : list1<(a,int)> ) : div tree { refs = xs.map(fst).map( fun(x) { (x, ref(0)) } ) wleafs = zip( refs.map(Leaf), xs.map(snd) ) tree = balance(wleafs) mark(0,tree) build(0,refs).fst }