Thanks, all, that gives me something to chew on.

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):

main :: IO()
main = do
  inputs <- getInputs
  doOutput $ f inputs initialState

f :: [input] -> state -> outputs

f [] state =
  transformToOutputs state

f (input:inputs) state =
  f inputs (newState state input)

doOutput :: [output] -> IO()

doOutput outputs = do
  putStr $ unlines outputs

So all I have to do is write newState and I'm good! ^_^

(transformToOutputs will, of course, be a snap.)

Right?

John.

On Thu, Dec 15, 2016 at 2:38 PM, Magnus Therning <magnus@therning.org> wrote:

John Lusk <john-haskell@how-hard-can-it-be.com> writes:

> I have not, but I might. This was a little work project that I've now run
> out of time for.
>
> I was really hoping for a deeper discussion of state management than
> "just use this package." This seems kind of like receiving a stream of
> inputs from a user and needing to keep track of several items of state
> that are changing independently (as opposed to the neat problems
> usually used in basic FP education).
>
> Should I be taking a more monadic approach?

Well, we have to start somewhere :)

Anyway, you don't necessarily have to resort to the state monad. I
believe, based you your other code that you quite easily can go from
your list of lines to a list of `(Int, String)`, where the integer
indicates the indentation level. Then you can look at `Data.Tree` (in
containers) and `Data.Tree.Zipper` (in rosezipper) to build your tree.

This is my quick hack:

~~~
buildTree _ zipPos [] = zipPos
buildTree n zipPos xx@((lvl, s):xs)
  | lvl > n =
    let newZipPos = children zipPos
        node = Node s []
    in buildTree lvl (insert node newZipPos) xs
  | lvl == n =
    let newZipPos = nextSpace zipPos
        node = Node s []
    in buildTree lvl (insert node newZipPos) xs
  | lvl < n =
    let (Just newZipPos) = parent zipPos
    in buildTree (n - 1) newZipPos xx
~~~

With the following definitions in place:

~~~
ils = [ (1, "The root")
      , (2, "Child 1")
      , (3, "Child 1.1")
      , (4, "Child 1.1.1")
      , (3, "Child 1.2")
      , (2, "Child 2")
      ]

zipRoot = fromTree $ Node "absolute top" []
~~~

I build the tree, and print it, like this:

~~~
putStrLn $ drawTree $ toTree $ buildTree 0 zipRoot ils
top
|
`- The root
   |
   +- Child 1
   |  |
   |  +- Child 1.1
   |  |  |
   |  |  `- Child 1.1.1
   |  |
   |  `- Child 1.2
   |
   `- Child 2
~~~

Whether this is usable for you depends a lot on how big your logs are, I
suppose.

If this was something that I'd keep around for a while I'd probably
look into rewriting `buildTree` so that it would fit for use with
`mapAccumL`.

/M

--
Magnus Therning              OpenPGP: 0x927912051716CE39
email: magnus@therning.org   jabber: magnus@therning.org
twitter: magthe               http://therning.org/magnus

The British have "the perfect temperament to be hackers—technically
skilled, slightly disrespectful of authority, and just a touch of
criminal behavior".
     — Mary Ann Davidson, Oracle's Security Chief

_______________________________________________
Beginners mailing list
Beginners@haskell.org
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners