Todd <t.greenwoodg...@gmail.com> writes: > My main question is, what tasks/apps is clojure ideally suited for? > > I've been playing with implementing Binary Search Trees in clojure and > Java as a way to learn clojure and compare the two languages. My > original thought was to implement some basic data types and algorithms > in a handful of interesting languages and compare the experience. For > me, the list includes clojure, java, scala, and erlang. > > So far, my experience implementing basic BST functionality in clojure > has felt contrived, and was definitely easier in java.
As others have said, implementing mutable data structures in Clojure is going against the grain of the language, just as it would be in any other opinionated functional language. You'd have much the same experience with Haskell. (Scala doesn't really count in this way, it's not opinionated.) Nevertheless since datatypes and protocols were introduced in Clojure 1.2 you *can* do it if you really need to. You'd never do this in a normal Clojure program, but you might need to when writing say a data structure library. Here's a loose translation of the binary search tree from the textbook "Foundations of Computer Science: C Edition" by Aho and Ullman. I'm just going to implement the first two functions: lookup and insert. Deletion, traversal and so on are much the same, just translate the C code directly to Clojure. BIG WARNING: I'm naming this "dangerous" on purpose, it's not thread safe and is very unclojurish. Do not use this data structure in a real Clojure program (or in any other language for that matter). It's very naive and really just plain bad. It is in the textbook to teach you the basics of trees, not because they recommend you actually use it. First up we need a protocol for a node struct with settable left and right child fields. (Yuck!) (defprotocol MutableBinaryNode (element [node]) (left [node]) (right [node]) (set-left! [node x]) (set-right! [node x])) Now the concrete implementation of the protocol, note that we annotate the "l" and "r" fields as :unsynchronized-mutable so that we can use set! on them. (Discouraged!) (deftype DangerousBinaryNode [el ^{:unsynchronized-mutable true} l ^{:unsynchronized-mutable true} r] MutableBinaryNode (element [this] el) (left [this] l) (right [this] r) (set-left! [this x] (set! l x)) (set-right! [this x] (set! r x))) Next the lookup function. It returns true if the element x is present in the search tree. This is basically identical to the C code except I'm using compare instead of < so that you can put strings and other objects in the BST, not just numbers. A good data structure would also let you specify an alternative comparator (see Clojure's sorted-set for example). (defn- lookup* [node x] (when node (let [rel (compare x (element node))] (cond (zero? rel) true (neg? rel) (recur (left node) x) (pos? rel) (recur (right node) x))))) Again insert is almost identical to the C code, just using a constructor instead of malloc: (defn- insert* [node x] (if (nil? node) (DangerousBinaryNode. x nil nil) (let [rel (compare x (element node))] (cond (neg? rel) (set-left! node (insert* (left node) x)) (pos? rel) (set-right! node (insert* (right node) x))) node))) Finally for usage convenience and so that we can have an empty BST, let's wrap that in a public API. All the above is implementation detail and shouldn't be exposed by a library. (defprotocol MutableSet (lookup [coll x]) (insert! [coll x])) (deftype DangerousBST [^{:unsynchronized-mutable true} root] MutableSet (lookup [this x] (lookup* root x)) (insert! [this x] (set! root (insert* root x)))) (defn dangerous-bst [] (DangerousBST. nil)) Now we can try it out: (def bst (dangerous-bst)) (insert! bst 1) (insert! bst 7) (lookup bst 1) ;; -> true (lookup bst 4) ;; -> nil (lookup bst 7) ;; -> true -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en