(module fib-join-forest mzscheme
(require (lib "etc.ss")
(lib "list.ss")
(lib "contract.ss")
(planet "contract-utils.ss" ("cobbe" "contract-utils.plt" 3 0)))
(define (join-forest a-forest node-join-f node-weight-f)
(concatenate-forest (foldl (lambda (a-node a-forest)
(add-node-to-forest a-node
a-forest
node-join-f
node-weight-f))
'()
a-forest)
node-join-f))
(define (add-node-to-forest a-node a-forest node-join-f node-weight-f)
(cond
[(empty? a-forest)
(list a-node)]
[(< (node-weight-f a-node)
(node-weight-f (first a-forest)))
(cons a-node a-forest)]
[else
(local
((define partial-forest
(merge-smaller-children a-forest
(node-weight-f a-node)
node-join-f
node-weight-f)))
(restore-forest-order (cons (node-join-f (first partial-forest)
a-node)
(rest partial-forest))
node-join-f
node-weight-f))]))
(define (concatenate-first-two a-forest node-join-f)
(cons (node-join-f (second a-forest)
(first a-forest))
(rest (rest a-forest))))
(define (merge-smaller-children a-forest n node-join-f node-weight-f)
(cond
[(empty? (rest a-forest))
a-forest]
[(<= (node-weight-f (first a-forest)) n)
a-forest]
[else
(merge-smaller-children (concatenate-first-two a-forest node-join-f)
n
node-join-f
node-weight-f)]))
(define (restore-forest-order a-forest node-join-f node-weight-f)
(cond
[(empty? (rest a-forest))
a-forest]
[(>= (node-weight-f (first a-forest))
(node-weight-f (second a-forest)))
(restore-forest-order (concatenate-first-two a-forest node-join-f)
node-join-f
node-weight-f)]
[else
a-forest]))
(define (concatenate-forest a-forest node-join-f)
(cond
[(empty? (rest a-forest))
(first a-forest)]
[else
(concatenate-forest (concatenate-first-two a-forest node-join-f)
node-join-f)]))
(provide/contract [join-forest
((nelistof/c any/c)
(any/c any/c . -> . any)
(any/c . -> . natural-number/c)
. -> . any)]))