This is the Clojure implementation of the Dictionary Trie previously implemented in Haskell. You can copy and paste it into a repl, or load it into a file. A basic usage goes:
(generate-trie
["rebate" "reborn" "realize" "real"])
or for fun
(println (generate-pretty
(generate-trie
["rebate" "reborn" "realize" "real" "relied"])))
to get the Dot
"_"[label="∅"]
"_"->"r_"[label=" r"]
"r_"[label="re"]
"r_"->"lr_"[label=" l"]
"r_"->"ar_"[label=" a"]
"r_"->"br_"[label=" b"]
"lr_"[label="lied(*)"]
"ar_"[label="al(*)"]
"ar_"->"iar_"[label=" i"]
"iar_"[label="ize(*)"]
"br_"[label="b"]
"br_"->"obr_"[label=" o"]
"br_"->"abr_"[label=" a"]
"obr_"[label="orn(*)"]
"abr_"[label="ate(*)"]
and copy those results here to see the image:
Discussion
- defmulti can be used to mimic Haskell's constructor/structure based dispatch
- Haskell has trained me to favor "higher-order" over macros. Higher-orders like partial, comp, etc. can do a lot of what you need.
- Looking forward to Clojure 1.2's defrecord capabilities as I have become a fan of abstract/algebraic data types
- Clojure has gotten a lot of mileage with the 80% of data structures we all use (in their immutable form): vector, hashmap, list. The upcoming defprotocol will allow the hard work for that last 20%
- as much as I love Haskell, you can't beat a quick (println) for debug.
- It was easier to mentally map the Haskell code to the Clojure code rather than re-reason the problem through.
- I like recur over hoping for a compiler TCO.
- Types do help debug. I found a lot of quirky edge-cases in testing Clojure run-time. Hard to put my finger on individual anecdotal evidence... more of a "feel thing".
- Just as in the Haskell implementation, I don't think there's any great advantage to be gained in using a zipper data structure. I will try though, mainly to familiarize myself with the zipper.
API Methods
- generate-trie
- query-node
- add-word-to-trie