Минималистская реализация:
(ns trie.example)
(defn trie-add [trie & words]
(reduce
(fn [trie word]
(assoc-in trie (concat word [::val]) word))
trie
words))
(defn trie-matches [trie prefix]
(letfn [(search [node]
(mapcat (fn [[k v]]
(if (= ::val k) [v] (search v)))
node))]
(search (get-in trie prefix))))
Пример использования:
;; Create trie
(def trie (trie-add {} "foo" "ba" "bar" "baz" "qux" "quux"))
;; trie looks like this:
{\q
{\u
{\u {\x {:trie.example/val "quux"}},
\x {:trie.example/val "qux"}}},
\b
{\a
{\z {:trie.example/val "baz"},
\r {:trie.example/val "bar"},
:trie.example/val "ba"}},
\f {\o {\o {:trie.example/val "foo"}}}}
;; Autocomplete
(trie-matches trie "ba")
=> ("baz" "bar" "ba")
Такие вещи, как сортировка, сохранение несловесных значений и сжатие, оставляются читателю в качестве упражнения.