;; -*- Scheme -*-
;;
;; $Id: avl-trie02.scm,v 1.1 1998/03/16 07:57:29 foner Exp $

;;-----------

(require 'avl-tree:merge-insert)
(require 'avl-tree:nil)
(require 'avl-tree:nil?)
(require 'avl-trie::node:key)
(require 'avl-trie::node:kids)
(require 'avl-trie::node:value)
(require 'avl-trie::node:+key)
(require 'avl-trie::node:+kids)
(require 'avl-trie::node:+value)

;;-----------

;;+doc
;; procedure: avl-trie:empty?
;; arguments: trie
;; signature: trie -> bool
;;
;; Returns #t if the TRIE is empty.
;;-doc

(define avl-trie:empty? avl-tree:nil?)


;;+doc
;; procedure: avl-trie:empty
;; arguments: none
;; signature: () -> trie
;;
;; Returns an empty TRIE.
;;-doc

(define avl-trie:empty (lambda () avl-tree:nil))

;;-----------

;;+doc
;; procedure: avl-trie:insert
;; arguments: trie keys <? if-exists[old xxx] if-not-exits[xxx] undefined
;; signature:
;;  forall a,b => trie[a,b] x [a] x (a x a -> bool) x (b x b -> b) x (b -> b)xb
;;             -> trie[a,b]
;;
;; Insert an element into TRIE.  KEYS is a list of the keys which
;; together with <? should form a strict partial order.  Note KEYS does not
;; have to be a proper list.  If it is not a proper list, it is assumed that
;; the tail of KEYS is the value to be inserted.  For example, if KEYS has
;; the form '(1 2 3 . "x"), then "x" is taken to the be value to be inserted.
;; If KEYS is a proper list, then the value to be inserted defaults to an 
;; empty list.  IF-EXISTS is called a value with the given KEYS already 
;; exists in the TRIE.  It takes the current value and the tail of KEYS 
;; as arguments and should return the value to be inserted.  Similarly
;; IF-NOT-EXISTS is called if an a value with the given KEYS is not already
;; in the TRIE.  It is also called with the tail of the KEYS and should return
;; the value to be inserted.  UNDEFINED is the value to be inserted into a
;; node in TRIE if that node does not contain a value.
;;
;; Examples:
;;
;; > (avl-trie:insert (avl-trie:empty) '(1 2 3 . "x") <
;; >                  (lambda (o v) v) (lambda (v) v) #f)
;;
;; This will insert the value "x" into the empty TRIE with the key (1 2 3).
;; The following is an alternative way of achieveing the same effect.
;;
;; > (let ((v "x"))
;; >   (avl-trie:insert (avl-trie:empty) '(1 2 3) <
;; >                    (lambda (o _) v) (lambda (_) v) #f))
;;-doc

(define avl-trie:insert
  (lambda (t ks <? if-exists if-not-exists u)
    (let loop ((t t) (k (car ks)) (ks (cdr ks)))
      (let ((if-found
	     (lambda (n)
	       (if (pair? ks)
		   (let ((kids (loop (avl-trie::node:kids n) (car ks) (cdr ks))))
		     (avl-trie::node:+kids kids n))
		   (let ((v (if-exists (avl-trie::node:value n) ks)))
		     (avl-trie::node:+value k v n)))))
	    (if-not-found
	     (lambda ()
	       (if (pair? ks)
		   (avl-trie::node k (loop (avl-trie:empty) (car ks) (cdr ks)) u)
		   (avl-trie::node k (avl-trie:empty) (if-not-exists ks))))))
	(avl-tree:merge-insert t k avl-trie::node:key <? if-found if-not-found)))))

;;-----------

;; eof
