Hi apfelmus,<br><br><div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">Your code is fine, I like it. A minor hint is that mergeForest is a fold:
<br>&nbsp;&nbsp; mergeForest = foldr merge []<br>Also, we have<br>&nbsp;&nbsp; prettyPrint = putStr . unlines . prettyPrint&#39; $ forest</blockquote><div><br>Nice help on the simple things. <br></div><br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
I can&#39;t know, but it doesn&#39;t seem unreasonable that you intend to use<br>the ArcForest as a trie, i.e. an efficient implementation of a set of<br>paths which allows to look up quickly whether a given path (here of type
<br>[String]) is in the set or not. So, we have</blockquote><div><br>For a while, I was thinking what on Earth are you talking about, even while I continued reading the rest of the email, but it eventually clicked what you where trying to show me - which was something I didn&#39;t dare try until I got more familiar with Haskell.
<br><br>You&#39;re examples got me started on dealing with these sorts of complex tree structures (or tries as you call them).&nbsp; They made more sense as I spent more time reading and rereading them.<br><br></div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
Now, we can build up our finite map for paths:<br><br>&nbsp;&nbsp; data MapPath v = TriePath (Maybe v) (MapString (MapPath v))<br><br>because it (maybe) contains a value for the key &#39;[] :: Path&#39; and it<br>(maybe) contains a map of paths that is organized by their first String
<br>element.</blockquote><div><br>In my own code I had to diverge from your definition because for my needs, every node needed to contain a value (even if it was a default value).&nbsp; I plan to later add other numerical values to every node so that I can traverse them and do calculations that feed up and trickle down the tree.
<br></div><br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">Now what about &#39;MapString v&#39;, how do we get this? Well, your<br>implementation corresponds to the choice
<br><br>&nbsp;&nbsp;type MapString v = [(String,v)]<br><br>But in our case, we can apply the same trick again! We have &#39;String =<br>[Char]&#39; and given an implementation of<br><br>&nbsp;&nbsp;data MapChar v = ...<br><br>we can use exactly the same code from &#39;MapPath v&#39; to implement
<br>&#39;MapString v&#39;! (This reuse can be abstracted into a type class, but I&#39;ll<br>not cover that here.) Of course, we need &#39;MapChar v&#39; now. But yet, again<br>we can think of Char as<br><br>&nbsp;&nbsp;Char ^= Int ^= [Bool]
<br><br>where the &#39;[Bool]&#39; means the list of digits in binary representation.<br>So, given &#39;MapBool v&#39;, we can implement &#39;MapChar v&#39; with yet again the<br>same code that we used for the preceding finite maps! Fortunately, the
<br>recursion ends here because a finite map for &#39;Bool&#39;eans is just the pair<br><br>&nbsp;&nbsp;type MapBool v = (Maybe v, Maybe v)</blockquote><div><br>That&#39;s quite beautiful, but I don&#39;t actually need to go that far.&nbsp; Question though, does taking the approach to this conclusion actually have real applications?
<br><br></div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">In case your head does not yet hurt too much :), further information<br>about tries in Haskell and a detailed explanation of why the code above
<br>works, can be found in.</blockquote><div><br>I did try to write my own insertWithInit called by fromPath (below), which I couldn&#39;t get working.&nbsp; Branches went missing from the result.&nbsp; I had so much trouble figuring where in the function I forgot to do something.
<br><br>At this point my head was about to explode, so I took a different approach using union called by fromList&#39; (also below), which from my limited testing appears to work.&nbsp; I also find the union function incredibly easy to understand.&nbsp; I only hope I got it right.
<br><br>Thanks much,<br><br>-John<br><br>import qualified Data.Map as Map<br>import Data.Map (Map)<br><br>type Path k = [k]<br><br>data Trie k v = Trie v (Map k (Trie k v)) deriving Show<br><br>singleton :: v -&gt; Trie k v
<br>singleton v = Trie v Map.empty<br><br>insertWithInit :: (Ord k) =&gt;<br>&nbsp; v -&gt; (v -&gt; v -&gt; v) -&gt; Path k -&gt; v -&gt; Trie k v -&gt; Trie k v<br>insertWithInit _ fInsert [] v (Trie v&#39; m) =<br>&nbsp; Trie (fInsert v v&#39;) m
<br>insertWithInit fInit fInsert (x:xs) v (Trie v&#39; m) =<br>&nbsp; Trie v&#39; (Map.insertWith merge x subTrie m)<br>&nbsp; where<br>&nbsp;&nbsp;&nbsp; subTrie = insertWithInit fInit fInsert xs v (singleton fInit)<br>&nbsp;&nbsp;&nbsp; merge = seq<br><br>-- Left biased union
<br>union :: (Ord k) =&gt; Trie k v -&gt; Trie k v -&gt; Trie k v<br>union (Trie k0 v0) (Trie k1 v1) = Trie k0 v<br>&nbsp; where<br>&nbsp;&nbsp;&nbsp; v = Map.unionWith union v0 v1<br><br>fromPath :: (Ord k) =&gt; v -&gt; v -&gt; Path k -&gt; Trie k v
<br>fromPath initV v path = foldr addParent (singleton v) path<br>&nbsp; where<br>&nbsp;&nbsp;&nbsp; addParent step child = Trie initV (Map.fromList [(step, child)])<br><br>fromList :: [Path String] -&gt; Trie String ()<br>fromList paths = foldl f (singleton ()) paths
<br>&nbsp; where<br>&nbsp;&nbsp;&nbsp; f :: Trie String () -&gt; Path String -&gt; Trie String ()<br>&nbsp;&nbsp;&nbsp; f trie path = insertWithInit () (\x y -&gt; ()) path () trie<br><br>fromList&#39; :: [Path String] -&gt; Trie String ()<br>fromList&#39; paths = foldl f (singleton ()) paths
<br>&nbsp; where<br>&nbsp;&nbsp;&nbsp; f :: Trie String () -&gt; Path String -&gt; Trie String ()<br>&nbsp;&nbsp;&nbsp; f trie path = union trie (fromPath () () path)<br><br>prettyPrint :: Trie String () -&gt; IO ()<br>prettyPrint trie = putStrLn $ unlines $ prettyPrint&#39; trie
<br>&nbsp; where<br>&nbsp;&nbsp;&nbsp; prettyPrint&#39; (Trie v m) = Map.foldWithKey f [] m<br>&nbsp;&nbsp;&nbsp; f k a out = out ++ [k] ++ (map (&quot; &quot; ++) (prettyPrint&#39; a))<br><br>&nbsp;</div><br></div>