
I thought this one would be easy but I'm starting to think its not. I am playing with HaXml and I want to transform an XML tree into another tree. The transforms are simple enough, but the kicker is that I want them to be "stateful." In this example, the state is a random number generator. So the transformation depends on the current node and the random number generator state. I want to transform every node in the tree. My feeble attempt at this is given in: http://www.thenewsh.com/~newsham/x/tweaker.hs What I see when I run it is that the value of "p" in the "tweak" function is identical each time. Indeed, it seems "g" itself is the same each time "tweak" is invoked (I wrote a variant of the program that used sequential integers instead of generators to verify this). So here's what I think is going on. You can probably skip this section because I am probably off base anyway... I guess "keep" is being applied to one node, and returning a list of 1 node, and this is zipped with my infinite list of generators and as a result I get the same generator each time. If this is the case I guess foldXml is not the right tool for this job. Perhaps I want a newly-written foldXml that works with LabelFilters rather than CFilters? Ok.. so what's really going on here. Can I do what I want to do? Whats the right tool to transform every node in the tree? Is there a more general approach to doing stateful transformations? Thanks in advance for letting me waste your time. P.S. any stylistic advice, or alternate approaches also welcome. The objective here is to learn... Tim Newsham http://www.thenewsh.com/~newsham/

Tim Newsham
I thought this one would be easy but I'm starting to think its not. I am playing with HaXml and I want to transform an XML tree into another tree. The transforms are simple enough, but the kicker is that I want them to be "stateful." In this example, the state is a random number generator. So the transformation depends on the current node and the random number generator state. I want to transform every node in the tree.
Indeed, the HaXml functions are pure, and in particular foldXml does not thread a state through. To introduce state, you provide your own state monad (fortunately there is always Control.Monad.State). To traverse the whole tree in this monad, you write your own recursion and deconstruct the nodes yourself (because foldXml is too specific to be re-usable). Here is my example. It replaces attribute values by random integers between 0 and 99, so it is a similar task but slightly different from yours. Some names are inspired by yours, but I have simplified their nature: The state I thread through is not a stream of generators, but rather a stream of numbers; as long as this stream comes from Random.randomRs, I'm good. import Text.XML.HaXml import Control.Monad.State import Random newtweak :: [Int] -> CFilter newtweak xs c = [evalState (reco c) xs] reco :: Content -> State [Int] Content reco (CElem (Elem nm ats cs)) = do { ats' <- mapM newtweakAttr ats ; cs' <- mapM reco cs ; return (CElem (Elem nm ats' cs')) } reco c = return c newtweakAttr (k,_) = do { n <- gets head ; modify tail ; return (k, AttValue[Left (show n)]) } main = do gen <- getStdGen processXmlWith (newtweak (randomRs (0,99) gen))
participants (2)
-
Albert Lai
-
Tim Newsham