[Haskell-cafe] Seeking advice on a style question

Conal Elliott conal at conal.net
Mon Dec 25 12:52:47 EST 2006


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.

Cheers, - Conal

On 12/24/06, Steve Schafer <steve at fenestra.com> wrote:
>
> In my text/graphics formatting work, I find myself doing a lot of
> "pipeline" processing, where a data structure will undergo a number of
> step-by-step transformations from input to output. For example, I have a
> function that looks like this (the names have been changed to protect
> the innocent--and to focus on the structure):
>
> process :: a -> b -> c -> d -> e
> process x1 x2 x3 x4 =
>    let y01       = f01 x1 x2 x3;
>        y02       = f02 x1;
>        y03       = f03 y02;
>        y04       = f04 y03;
>        y05       = f05 x1 y01 y04;
>        y06       = f06 x2 y05;
>        (y07,y08) = f07 y01 y06;
>        y09       = f08 y07;
>        (y10,y11) = f09 x2 x4 y09 y08;
>        y12       = f10 y10;
>        y13       = f11 y12;
>        y14       = f12 x1 x2 x3 y01 y13;
>        y15       = f13 y14;
>        y16       = f14 y15 y11
>        in y16
>
> As you can see, the process is somewhat imperative in overall
> appearance, with each intermediate function f01..f14 accepting some
> combination of the original input values and/or intermediate values and
> returning a new value (or, in some cases, a tuple of values).
>
> Obviously, not all of the steps need to be broken out this way. We can,
> for example, skip the second and third steps and directly write:
>
> y04 = f04 $ f03 $ f02 x1;
>
> Laying it out this way has a couple of advantages. It makes the steps in
> the process transparently clear, and if I discover at some point that I
> need to make a change (e.g., a new requirement causes f13 to need access
> to x2), it's perfectly obvious where to make the modifications.
>
> Nevertheless, it also looks like something that would be amenable to
> processing with a State monad, except for one thing: The "shape" of the
> state isn't constant throughout the process. At any given step, new
> information may be added to the state, and old information may be thrown
> away, if there is no further need for it. In principle, it could be
> managed with a bunch of nested StateT monads, but my attempts to do so
> seem to get so caught up in the bookkeeping that I lose the advantages
> mentioned above.
>
> Alternatively, I can wrap all of the state up into a single universal
> structure that holds everything I will ever need at every step, but
> doing so seems to me to fly in the face of strong typing; at the early
> stages of processing, the structure will have "holes" in it that don't
> contain useful values and shouldn't be accessed.
>
> So here's the question: Is there a reasonable way to express this kind
> of process (where I suppose that "reasonable" means "in keeping with
> Haskell-nature") that preserves the advantages mentioned above, but
> avoids having to explicitly pass all of the various bits of state
> around? The (unattainable?) ideal would be something that looks like
> this:
>
> process = f14 . f13 . ... . f01
>
> or
>
> process = f01 >>= f02 >>= ... >>= f14
>
> Steve Schafer
> Fenestra Technologies Corp.
> http://www.fenestra.com/
> _______________________________________________
> Haskell-Cafe mailing list
> Haskell-Cafe at haskell.org
> http://www.haskell.org/mailman/listinfo/haskell-cafe
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.haskell.org/pipermail/haskell-cafe/attachments/20061225/f3033c19/attachment-0001.htm


More information about the Haskell-Cafe mailing list