I'm not sure this example really has anything to do with state. Is there anything about your domain & examples that differs from standard functional programming (or math)? To my eye, your example code below looks less like an imperative program than like an intermediate form that a compiler would generate from an expression built up from nested function applications and a few "let"s.
<br><br>Cheers, - Conal<br><br><div><span class="gmail_quote">On 12/24/06, <b class="gmail_sendername">Steve Schafer</b> <<a href="mailto:firstname.lastname@example.org">email@example.com</a>> wrote:</span><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
In my text/graphics formatting work, I find myself doing a lot of<br>"pipeline" processing, where a data structure will undergo a number of<br>step-by-step transformations from input to output. For example, I have a
<br>function that looks like this (the names have been changed to protect<br>the innocent--and to focus on the structure):<br><br> process :: a -> b -> c -> d -> e<br> process x1 x2 x3 x4 =<br> let y01 = f01 x1 x2 x3;
<br> y02 = f02 x1;<br> y03 = f03 y02;<br> y04 = f04 y03;<br> y05 = f05 x1 y01 y04;<br> y06 = f06 x2 y05;<br> (y07,y08) = f07 y01 y06;<br> y09 = f08 y07;
<br> (y10,y11) = f09 x2 x4 y09 y08;<br> y12 = f10 y10;<br> y13 = f11 y12;<br> y14 = f12 x1 x2 x3 y01 y13;<br> y15 = f13 y14;<br> y16 = f14 y15 y11<br> in y16
<br><br>As you can see, the process is somewhat imperative in overall<br>appearance, with each intermediate function f01..f14 accepting some<br>combination of the original input values and/or intermediate values and<br>returning a new value (or, in some cases, a tuple of values).
<br><br>Obviously, not all of the steps need to be broken out this way. We can,<br>for example, skip the second and third steps and directly write:<br><br> y04 = f04 $ f03 $ f02 x1;<br><br>Laying it out this way has a couple of advantages. It makes the steps in
<br>the process transparently clear, and if I discover at some point that I<br>need to make a change (e.g., a new requirement causes f13 to need access<br>to x2), it's perfectly obvious where to make the modifications.
<br><br>Nevertheless, it also looks like something that would be amenable to<br>processing with a State monad, except for one thing: The "shape" of the<br>state isn't constant throughout the process. At any given step, new
<br>information may be added to the state, and old information may be thrown<br>away, if there is no further need for it. In principle, it could be<br>managed with a bunch of nested StateT monads, but my attempts to do so
<br>seem to get so caught up in the bookkeeping that I lose the advantages<br>mentioned above.<br><br>Alternatively, I can wrap all of the state up into a single universal<br>structure that holds everything I will ever need at every step, but
<br>doing so seems to me to fly in the face of strong typing; at the early<br>stages of processing, the structure will have "holes" in it that don't<br>contain useful values and shouldn't be accessed.<br>
<br>So here's the question: Is there a reasonable way to express this kind<br>of process (where I suppose that "reasonable" means "in keeping with<br>Haskell-nature") that preserves the advantages mentioned above, but
<br>avoids having to explicitly pass all of the various bits of state<br>around? The (unattainable?) ideal would be something that looks like<br>this:<br><br> process = f14 . f13 . ... . f01<br><br>or<br><br> process = f01 >>= f02 >>= ... >>= f14
<br><br>Steve Schafer<br>Fenestra Technologies Corp.<br><a href="http://www.fenestra.com/">http://www.fenestra.com/</a><br>_______________________________________________<br>Haskell-Cafe mailing list<br><a href="mailto:Haskell-Cafe@haskell.org">