<div dir="ltr">Thanks for the reply.  That is an interesting alternative I hadn't considered.  What I end up with applying it to flow charts is something like the following<div><br></div><div>    data FlowChart m a where</div><div>      Decision :: m Bool -> FlowChart m a -> FlowChart m a -> FlowChart m a</div><div>      Done :: m a -> FlowChart m a</div><div><br></div><div>    runFlowChart :: FlowChart m a -> m a</div><div>    runFlowChart (Decision cond falsePath truePath) = cond >>= \c -> runFlowChart (if c truePath else falsePath)</div><div>    runFlowChart (Done a) = a</div><div><br></div><div>    s0 = Decision testS0 s1 s2</div><div>    s1 = Done s1Result</div><div>    s2 = Done s2Result</div><div><br></div><div>This is simpler than what I was trying to do. It should have all the same benefits as well. I'm going to give this a spin and see how it goes. Thanks!</div><div><br></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Fri, Dec 26, 2014 at 1:39 AM, Stephen Tetley <span dir="ltr"><<a href="mailto:stephen.tetley@gmail.com" target="_blank">stephen.tetley@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hi Richard<br>
<br>
It might be worth looking at Wyatt Allan and Martin Erwig's Surveyor<br>
DSEL for alternative design ideas. The authors directly encode<br>
questions rather than states which, without looking closely, seems<br>
more natural to me - I think you could envisage flow diagrams as<br>
specializations of "surveys".<br>
<br>
The paper is available from Martin's website:<br>
<br>
<a href="http://web.engr.oregonstate.edu/~erwig/papers/abstracts.html" target="_blank">http://web.engr.oregonstate.edu/~erwig/papers/abstracts.html</a><br>
<br>
Best wishes<br>
<br>
Stephen<br>
<br>
On 25 December 2014 at 23:34, Richard Wallace<br>
<div><div class="h5"><<a href="mailto:rwallace@thewallacepack.net">rwallace@thewallacepack.net</a>> wrote:<br>
> Hello,<br>
><br>
> I've been working to encode a fairly complex flow chart. At first I took the<br>
> simple approach of having a single data type for the possible states<br>
><br>
>     data S = S0 | S1 | S2<br>
><br>
> and then a simple recursive function to step through it<br>
><br>
>     loop :: Monad m => S -> StateT s m Result<br>
>     loop S0 = testS0 >>= \r -> if r then loop S1 else loop S2<br>
>     loop S1 = s1Result<br>
>     loop S2 = s2Result<br>
><br>
> This works well enough, but with the size of the flow chart I'm working with<br>
> (50+ decision points) it quickly becomes clear that it's probably not the<br>
> most best way to do it.  One problem that I'd like to solve is being able to<br>
> test each decision point in isolation, making sure that decision point `m`<br>
> will go to decision point `n` when it is supposed to, without having to run<br>
> through the whole rest of the flow chart that would otherwise follow.<br>
> Something else I'd like to achieve is being able to organize the decisions<br>
> into separate modules - much better than having just the one big function<br>
> above.<br>
><br>
> Here's what I've come up with as an alternative so far.<br>
><br>
>     data Step a b where<br>
>       TrueFlow :: Decision a d e => a -> Step a b<br>
>       FalseFlow :: Decision b f g => b -> Step a b<br>
>       Done :: Result -> Step a b<br>
><br>
>     class Decision a b c | a -> b, a -> c where<br>
>       decide :: (Functor m, Monad m) => a -> StateT s m (Step b c)<br>
><br>
>     data S0 = S0 deriving (Show, Eq)<br>
>     instance Decision S0 S1 S2 where<br>
>       decide _ = bool (FalseFlow S2) (TrueFlow S1) <$> testS0<br>
><br>
>     data S1 = S1 deriving (Show, Eq)<br>
>     instance Decision S1 () () where<br>
>       decide _ = s1Result<br>
><br>
>     data S2 = S2 deriving (Show, Eq)<br>
>     instance Decision S2 () () where<br>
>       decide _ = s2Result<br>
><br>
>     decision :: (Functor m, Monad m, Decision a b c)<br>
>                  => a<br>
>                  -> StateT s m Result<br>
>     decision s = decide s >>= \case<br>
>       TrueFlow b -> decision b<br>
>       FalseFlow c -> decision c<br>
>       Done s -> return s<br>
><br>
> With this implementation it is easy to test a single decision point, - just<br>
> use `evalStateT (decide S0) s` and compare the resulting Step to make sure<br>
> it is either S1 or S2.  The logic can also be easily separated and organized<br>
> into modules.<br>
><br>
> The biggest drawback of this new approach is the need to create a new `Step`<br>
> record at every decision point.  In the end, this may be worth it for the<br>
> added design benefits, but would love to be able to get rid of it and find a<br>
> solution that gives the added benefits without incurring any performance<br>
> penalties.<br>
><br>
> Any suggestions anyone can give on improvements would be greatly<br>
> appreciated.<br>
><br>
> Thanks!<br>
> Rich<br>
><br>
</div></div>> _______________________________________________<br>
> Haskell-Cafe mailing list<br>
> <a href="mailto:Haskell-Cafe@haskell.org">Haskell-Cafe@haskell.org</a><br>
> <a href="http://www.haskell.org/mailman/listinfo/haskell-cafe" target="_blank">http://www.haskell.org/mailman/listinfo/haskell-cafe</a><br>
><br>
</blockquote></div><br></div>