The following problem has been taxing me.... I have a list of pairs that I have parsed from a input file, which represent a hiirarchy, where the first element is the name of the object, and the second is the name of the parent if there is one: type ParseOutput = [(String,Maybe String)] I wish to convert this to a list of "objects", where from each object I can navigate to the parent object (if any), or the children (if any): data Obj = Obj { name::String, parent::(Maybe Obj), children::[Obj] } type Result = [Obj] convert:: ParseOutput -> Result In a language with mutable references, this would be a relatively straightforward. I would just create a dictionary mapping from name to Obj, and then iterate over them, filling in the parents and children where appropriate. odict = {} for (name,parent) in parseOutput: odict[name] = Obj() for (name,parent) in parseOutput: if parent: parent = odict[parent] child = odict[name] child.parent = parent parent.children.append( child ) This gives away my background! How can I do this in Haskell? If I don't have mutable references, I figure that I must need to use laziness in some way, perhaps similar to how I would build an infinite structure. A hint or two would be great. Tim
Timothy Docker writes:
[...] How can I do this in Haskell? If I don't have mutable references, I figure that I must need to use laziness in some way, perhaps similar to how I would build an infinite structure.
http://www.mail-archive.com/haskell@haskell.org/msg06321.html I have nothing to add to that explanation, so will conserve bandwidth by
Tom Pledger writes:
Timothy Docker writes:
[...] How can I do this in Haskell? If I don't have mutable references, I figure that I must need to use laziness in some way, perhaps similar to how I would build an infinite structure.
http://www.mail-archive.com/haskell@haskell.org/msg06321.html
To be honest, I found this code quite confusing, I think because of the way in which a the "tail" needs to be joined back to the "head" in creating a circular data structure. I did eventually come up with a solution that seems straightforward enough, although I have no idea of its efficiency... | type ParseOutput = [(String,Maybe String)] | | data Obj = Obj { oname::String, | oparent::(Maybe Obj), | ochildren::[Obj] } | | convert:: ParseOutput -> [Obj] | convert output = converted | where converted = map mkObj output | mkObj (name,parent) = (Obj name | (fmap (findObj converted) parent) | (filter (hasParentNamed name) converted) ) | | findObj:: [Obj] -> String -> Obj | findObj [] name = error ("No object with name "++name) | findObj (o:os) name | name == (oname o) = o | | otherwise = findObj os name | | hasParentNamed :: String -> Obj -> Bool | hasParentNamed name obj = maybe False ((==name).oname) (oparent obj) | Thanks for the pointer. Tim
participants (2)
-
Timothy Docker -
Tom Pledger