Subject: Interesting Side-Effects Problem & Solution From: Avi Kivity <Avi@xxxxxxxxxxxxx> Date: Thu, 10 Dec 1998 19:52:24 +0200 |
I have recently come across a difficult problem which I would like to share with the list: My data contains empty <page> elements interspersed with the content elements (no, I'm not using them to control pagination). The problem is to locate the nearest <page> element that precedes some given element in tree order. This <page> element may be a sibling node, or it may occur as some other type of relative (cousin-node?). Locating the <page> element is possible by using node navigation, however this is very costly (O(number of separating nodes)). A trivial C++ implementation comes to mind: add a unique pageid attribute to <page> elements, and corresponding pageidref attributes to all other nodes, and fill them in some sort of prepass. The output would look something like this: <root> <page pageid="p0"> <section pageidref="p0" -- comes from sibling -- > blah blah <section pageidref="p0" -- comes from sibling of parent -- > more blah blah <page pageid="p1"> goo goo </section> <section pageid="p1" -- comes from child of sibling -- > <!-- etc --> </root> When trying to contemplate a dsssl implementation, however, I hit the famous no-side-effects-here barrier. The element processing rules only return sosofos, while more information (the page element to be linked) is required. So I decided to implement my own rule driver using node-list-reduce: (define (process-with-side-effects nl obj) (node-list-reduce nl (lambda(obj snl) ((cdr obj) (car obj) snl)) obj ) ) Where an obj is a pair (value . rule). Value is the result of the operation (usually a sosofo), and rule is a procedure object that combines a value with a node, returning a new obj. An example rule is: (define example-rule (lambda(sosofo snl) (if (is-element? snl) (let ( (recurse (process-with-side-effects (children snl) (cons (empty-sosofo) example-rule) ) ) ) (cons (sosofo-append sosofo (make element gi: snl attributes: (copy-attributes snl) (car recurse) ;processing result of children ) ) (cdr recurse) ;propagate state from children ) ) (cons ;non-element node (sosofo-append sosofo (process-node-list snl) ) example-rule ) ) ) ) This is a fairly verbose (and lacking) version of the jade identity transform. Things become interesting, however, when the rule is defined as: (define (interesting-rule parameter) (lambda(sosofo snl) ... (do-something-with parameter) ... (cons a-sosofo (interesting-rule (+ parameter 1)) ;successors use a different rule ) ... ) ) Now, results from processing of a node propagate to its successor, and results from processing of the children of a node propagate upwards to the successor of their parent. Implementing my original problem becomes trivial. And each node is traversed exactly once. (An aside: a 'with-mode' would be implemented by returning an altogether different rule rather than a variant of the current rule) My questions to the list are: 1. Has anyone survived this long message? 2. Are there other generic solutions to this type of problem? Better? Worse? 3. How would this be accomplished when the transformation language becomes available? 4. When would the transformation language become available? ;) (make empty-element gi: "sig" attributes: '(("name" "Avi Kivity") ("email" "avi@xxxxxxxxxxxxx"))) --------------------- "Thou shalt not travel faster than light" - Carl Sagan, Contact DSSSList info and archive: http://www.mulberrytech.com/dsssl/dssslist
Current Thread |
---|
|
<- Previous | Index | Next -> |
---|---|---|
RE: Capitalizing a string?, Frank A. Christoph | Thread | Re: Interesting Side-Effects Proble, Henry S. Thompson |
Re: Page numbers, margn spaces and , Tony Graham | Date | Re: 3 questions, Norman Walsh |
Month |