<div dir="ltr">Thanks, all, that gives me something to chew on.<div><br></div><div>It occurred to me (during my 45-minute commute to work) that all Haskell programs (listen to the noob <eyeroll/>) have the following structure (modulo my fractured syntax):</div><div><br></div><div><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div><div><font face="monospace, monospace">main :: IO()</font></div><div><font face="monospace, monospace">main = do</font></div><div><font face="monospace, monospace">  inputs <- getInputs</font></div><div><font face="monospace, monospace">  doOutput $ f inputs initialState</font></div><div><font face="monospace, monospace"><br></font></div><div><font face="monospace, monospace">f :: [input] -> state -> outputs</font></div><div><font face="monospace, monospace"><br></font></div><div><font face="monospace, monospace">f [] state =</font></div><div><font face="monospace, monospace">  transformToOutputs state</font></div><div><font face="monospace, monospace"><br></font></div><div><font face="monospace, monospace">f (input:inputs) state =</font></div><div><font face="monospace, monospace">  f inputs (newState state input)</font></div><div><font face="monospace, monospace"><br></font></div><div><font face="monospace, monospace">doOutput :: [output] -> IO()</font></div><div><font face="monospace, monospace"><br></font></div><div><font face="monospace, monospace">doOutput outputs = do</font></div><div><font face="monospace, monospace">  putStr $ unlines outputs</font></div><div><br></div></div></blockquote>So all I have to do is write newState and I'm good! ^_^</div><div><br></div><div>(transformToOutputs will, of course, be a snap.)</div><div><br></div><div>Right?</div><div><br></div><div>John.</div></div><div class="gmail_extra"><br><div class="gmail_quote">On Thu, Dec 15, 2016 at 2:38 PM, Magnus Therning <span dir="ltr"><<a href="mailto:magnus@therning.org" target="_blank">magnus@therning.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class=""><br>
John Lusk <<a href="mailto:john-haskell@how-hard-can-it-be.com">john-haskell@how-hard-can-it-<wbr>be.com</a>> writes:<br>
<br>
> I have not, but I might. This was a little work project that I've now run<br>
> out of time for.<br>
><br>
> I was really hoping for a deeper discussion of state management than<br>
> "just use this package." This seems kind of like receiving a stream of<br>
> inputs from a user and needing to keep track of several items of state<br>
> that are changing independently (as opposed to the neat problems<br>
> usually used in basic FP education).<br>
><br>
> Should I be taking a more monadic approach?<br>
<br>
</span>Well, we have to start somewhere :)<br>
<br>
Anyway, you don't necessarily have to resort to the state monad. I<br>
believe, based you your other code that you quite easily can go from<br>
your list of lines to a list of `(Int, String)`, where the integer<br>
indicates the indentation level. Then you can look at `Data.Tree` (in<br>
containers) and `Data.Tree.Zipper` (in rosezipper) to build your tree.<br>
<br>
This is my quick hack:<br>
<br>
~~~<br>
buildTree _ zipPos [] = zipPos<br>
buildTree n zipPos xx@((lvl, s):xs)<br>
  | lvl > n =<br>
    let newZipPos = children zipPos<br>
        node = Node s []<br>
    in buildTree lvl (insert node newZipPos) xs<br>
  | lvl == n =<br>
    let newZipPos = nextSpace zipPos<br>
        node = Node s []<br>
    in buildTree lvl (insert node newZipPos) xs<br>
  | lvl < n =<br>
    let (Just newZipPos) = parent zipPos<br>
    in buildTree (n - 1) newZipPos xx<br>
~~~<br>
<br>
With the following definitions in place:<br>
<br>
~~~<br>
ils = [ (1, "The root")<br>
      , (2, "Child 1")<br>
      , (3, "Child 1.1")<br>
      , (4, "Child 1.1.1")<br>
      , (3, "Child 1.2")<br>
      , (2, "Child 2")<br>
      ]<br>
<br>
zipRoot = fromTree $ Node "absolute top" []<br>
~~~<br>
<br>
I build the tree, and print it, like this:<br>
<br>
~~~<br>
putStrLn $ drawTree $ toTree $ buildTree 0 zipRoot ils<br>
top<br>
|<br>
`- The root<br>
   |<br>
   +- Child 1<br>
   |  |<br>
   |  +- Child 1.1<br>
   |  |  |<br>
   |  |  `- Child 1.1.1<br>
   |  |<br>
   |  `- Child 1.2<br>
   |<br>
   `- Child 2<br>
~~~<br>
<br>
Whether this is usable for you depends a lot on how big your logs are, I<br>
suppose.<br>
<br>
If this was something that I'd keep around for a while I'd probably<br>
look into rewriting `buildTree` so that it would fit for use with<br>
`mapAccumL`.<br>
<span class=""><br>
/M<br>
<br>
--<br>
Magnus Therning              OpenPGP: 0x927912051716CE39<br>
email: <a href="mailto:magnus@therning.org">magnus@therning.org</a>   jabber: <a href="mailto:magnus@therning.org">magnus@therning.org</a><br>
twitter: magthe               <a href="http://therning.org/magnus" rel="noreferrer" target="_blank">http://therning.org/magnus</a><br>
<br>
</span>The British have "the perfect temperament to be hackers—technically<br>
skilled, slightly disrespectful of authority, and just a touch of<br>
criminal behavior".<br>
     — Mary Ann Davidson, Oracle's Security Chief<br>
<br>______________________________<wbr>_________________<br>
Beginners mailing list<br>
<a href="mailto:Beginners@haskell.org">Beginners@haskell.org</a><br>
<a href="http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners" rel="noreferrer" target="_blank">http://mail.haskell.org/cgi-<wbr>bin/mailman/listinfo/beginners</a><br>
<br></blockquote></div><br></div>