Often the best way to get the “feel” of a new language is to look at some real code. Preferably code that does a non-trivial task, but a task with which you are generally familiar. To this end I’m posting here the code for a binary-tree representation of a dictionary. There are three files: the binary tree itself, a test suite using gUnit, and a simple visualization of the tree using Knuth’s algorithm. (This algorithm never re-uses a horizontal position, so it’s not much good for large trees.)
I was particularly pleased with the way that Grace’s blocks (λ-expressions) and lexical scope simplified the tricky problem of inserting nodes into the tree. What’s the “tricky problem”? To insert a node, one has to update a reference in an ancestor node, which might be the root, or the left of a parent node, or the right of a parent node. Handling each case separately leads to a combinatorial explosion of special cases. Here is the solution in Grace: at()put()
is the public (interface) method, and addNode()in()setParent()
the internal (confidential) recursive method that actually does the insertion.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
method at(key) put(value) { addNode(nodeContaining(key, value)) in (root) setParent { new → root := new } eventCount := eventCount + 1 self } method addNode(newNode) in (r) setParent (setParentRef) is confidential { // Adds newNode to the binary search tree rooted at r. setParentRef // is a block that is used to modify the final step of the path by // which this node was reached. if (r.isEmpty) then { setParentRef.apply(newNode) size := size + 1 } elseif (newNode.key == r.key) then { r.value := newNode.value } elseif { newNode.key ≤ r.key } then { addNode(newNode) in (r.left) setParent { new → r.left := new } } else { addNode(newNode) in (r.right) setParent { new → r.right := new } } } |
The “trick” that lets us use the same code in all situations is for the requestor of addNode…
to pass as an argument the code snippet that, when executed, will update the appropriate parent reference. The same trick works for deleting a node; see the whole module here.
If you want to try out this code yourself, you can do so using the web-based IDE (which you should open in Chrome or Firefox). Here is the tree visualization code running in the IDE.
The code examples do not run in the web-based ide anymore and stop with syntax errors.
Thanks for pointing this out. I’m afraid that many of the post here are out of date with respect to the current version of Grace. I’ve just updated the links so that they point to working code.