2024-09-04 02:16:10 -04:00
|
|
|
;;; Copyright (C) Peter McGoron 2024
|
|
|
|
;;; This program is free software: you can redistribute it and/or modify
|
|
|
|
;;; it under the terms of the GNU General Public License as published by
|
|
|
|
;;; the Free Software Foundation, version 3 of the License.
|
|
|
|
;;;
|
|
|
|
;;; This program is distributed in the hope that it will be useful,
|
|
|
|
;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
;;; GNU General Public License for more details.
|
|
|
|
;;;
|
|
|
|
;;; You should have received a copy of the GNU General Public License
|
|
|
|
;;; along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
;;; ;;;;;;;;;;;;;;
|
|
|
|
;;; Character maps
|
|
|
|
;;; ;;;;;;;;;;;;;;
|
|
|
|
|
|
|
|
(define char<=>
|
|
|
|
(lambda (x y)
|
|
|
|
(let ((x (char->integer x))
|
|
|
|
(y (char->integer y)))
|
|
|
|
(cond
|
|
|
|
((< x y) '<)
|
|
|
|
((= x y) '=)
|
|
|
|
(else '>)))))
|
|
|
|
|
|
|
|
|
|
|
|
(define %charmap:<=> (set:<=>-to-map char<=>))
|
|
|
|
(define %charmap:update (set:update %charmap:<=>))
|
|
|
|
|
|
|
|
(define charmap:update (map:update %charmap:update))
|
|
|
|
(define charmap:insert (map:insert %charmap:update))
|
|
|
|
(define charmap:search (map:search %charmap:<=>))
|
|
|
|
|
|
|
|
;;; ;;;;;;;;;;
|
|
|
|
;;; Char tries
|
2024-09-05 03:03:22 -04:00
|
|
|
;;;
|
|
|
|
;;; Tries are pairs, CAR = backing map from chars to trie nodes, and
|
|
|
|
;;; CDR = function tied to this part of the trie.
|
2024-09-04 02:16:10 -04:00
|
|
|
;;; ;;;;;;;;;;
|
|
|
|
|
2024-09-05 03:03:22 -04:00
|
|
|
;;; (TRIE:NEW TABLE FUNCTION)
|
2024-09-04 02:16:10 -04:00
|
|
|
(define trie:new cons)
|
2024-09-05 03:03:22 -04:00
|
|
|
(define trie:empty (trie:new '() #f))
|
|
|
|
|
|
|
|
;;; Get the function inside of trie NODE.
|
2024-09-04 02:16:10 -04:00
|
|
|
(define trie:function
|
|
|
|
(lambda (node)
|
|
|
|
(if (null? node)
|
|
|
|
#f
|
2024-09-05 03:03:22 -04:00
|
|
|
(cdr node))))
|
|
|
|
|
|
|
|
;;; Get the backing set inside of trie NODE.
|
|
|
|
(define trie:backing
|
2024-09-04 02:16:10 -04:00
|
|
|
(lambda (node)
|
|
|
|
(if (null? node)
|
|
|
|
'()
|
2024-09-05 03:03:22 -04:00
|
|
|
(car node))))
|
2024-09-04 02:16:10 -04:00
|
|
|
|
|
|
|
;;; Insert STRING-AS-LIST into NODE with value FUNCTION.
|
|
|
|
(define trie:insert
|
|
|
|
(lambda (node string-as-list function)
|
|
|
|
(if (null? string-as-list)
|
2024-09-05 03:03:22 -04:00
|
|
|
(trie:new (trie:backing node) function)
|
2024-09-04 02:16:10 -04:00
|
|
|
(let ((ch (car string-as-list))
|
|
|
|
(string-as-list (cdr string-as-list)))
|
2024-09-05 03:03:22 -04:00
|
|
|
(let ((newtree (charmap:update (trie:backing node) ch
|
2024-09-04 02:16:10 -04:00
|
|
|
(lambda (node oldnode)
|
|
|
|
(if oldnode
|
|
|
|
(map:node-new-val
|
|
|
|
oldnode
|
|
|
|
ch
|
|
|
|
(trie:insert (map:val oldnode)
|
|
|
|
string-as-list
|
|
|
|
function))
|
|
|
|
(map:empty-node ch
|
|
|
|
(trie:insert
|
|
|
|
trie:empty
|
|
|
|
string-as-list
|
|
|
|
function)))))))
|
2024-09-05 03:03:22 -04:00
|
|
|
(trie:new newtree (trie:function node)))))))
|
2024-09-04 02:16:10 -04:00
|
|
|
|
|
|
|
(define trie:insert-many
|
|
|
|
(lambda (node lst)
|
|
|
|
(fold (lambda (pair node)
|
2024-09-05 03:03:22 -04:00
|
|
|
(let ((key (car pair)))
|
|
|
|
(let ((key (cond
|
|
|
|
((list? key) key)
|
|
|
|
((string? key) (string->list key))
|
|
|
|
((char? key) (list key)))))
|
|
|
|
(trie:insert node key (cdr pair)))))
|
2024-09-04 02:16:10 -04:00
|
|
|
node lst)))
|
|
|
|
|
|
|
|
;;; Search for CH in NODE.
|
|
|
|
(define trie:search-single
|
|
|
|
(lambda (ch node)
|
|
|
|
(if (null? node)
|
|
|
|
'()
|
2024-09-05 03:03:22 -04:00
|
|
|
(let ((node (charmap:search (trie:backing node) ch)))
|
2024-09-04 02:16:10 -04:00
|
|
|
(if (null? node)
|
|
|
|
'()
|
|
|
|
(map:val node))))))
|
|
|
|
|
|
|
|
(define trie:search
|
|
|
|
(lambda (node str)
|
|
|
|
(fold trie:search-single node (string->list str))))
|
|
|
|
|
|
|
|
;;; ;;;;;
|
|
|
|
;;; Tests
|
|
|
|
;;; ;;;;;
|
|
|
|
|
|
|
|
(define %trie:tests
|
|
|
|
(list
|
|
|
|
(cons "insert with prefixes"
|
|
|
|
(lambda ()
|
|
|
|
(let ((trie
|
|
|
|
(trie:insert-many trie:empty
|
|
|
|
(list
|
|
|
|
(cons (string #\a #\b #\c #\d) 10)
|
|
|
|
(cons (string #\a #\b #\c) 20)
|
|
|
|
(cons (string #\a #\b #\c #\d #\e) 30)
|
|
|
|
(cons (string #\b) 40)
|
|
|
|
(cons (string #\b #\e #\g) 50))))
|
|
|
|
(t '()))
|
|
|
|
(set! t (trie:search trie (string #\a #\b #\c)))
|
|
|
|
(if (not (= (trie:function t) 20))
|
|
|
|
"abc not found"
|
|
|
|
(let ((t (trie:search-single #\d t)))
|
|
|
|
(if (not (= (trie:function t) 10))
|
|
|
|
"abcd not found"
|
|
|
|
(let ((t (trie:search-single #\e t)))
|
|
|
|
(if (not (= (trie:function t) 30))
|
|
|
|
"abcde not found"
|
|
|
|
(let ((t (trie:search-single #\b trie)))
|
|
|
|
(if (not (= (trie:function t) 40))
|
|
|
|
"b not found"
|
|
|
|
(let ((t (trie:search t (string #\e #\g))))
|
|
|
|
(= (trie:function t) 50))))))))))))))
|