Optimally iterating in Haskell with termination conditions and differing iteration steps

Go To StackoverFlow.com

0

I am trying to write a simple iterating algorithm in Haskell, but I'm struggling to find the optimal solution in terms of elegance and speed.

I have an algorithm that needs to apply an operation to a state over a number of iterations until some stopping condition is reached, recording the state using some arbitrary function. I already know how to implement a scheme like this by defining a function like iterateM.

But in this case the operation to perform for each step depends on the state, and boils down to checking a 'step type' condition to decide on the next iteration types, and then performing operation A for the next 10 iterations, or performing operation B for the next iteration before checking the condition again.

I could write it in an imperative style as:

c=0
while True:
    if c>0:
        x=iterateByA(x)
        c=c-1
    else:
        if stepCondition(x)==0:
            x=iterateByA(x)
            c=9
        else:
           x=iterateByB(x)
    observeState(x)
    if stopCondition(x):
        break

and of course this could just be copied in Haskell, but I would rather do something more elegant.

My idea is to have the iteration use a list of functions to pop and apply to the state, and update that list with a new one (based on the 'step type' condition) once it is empty. I'm slightly concerned that this will be inefficient though. Would doing this and using something like

take 10 (repeat iterateByA)

compile away all of the list allocation etc to a tight loop that only uses a counter, like the imperative one above?

Is there another neat and efficient way of doing this?

If it helps this is for an adaptive stochastic simulation algorithm, the iteration steps update the state and the step condition (that decides the best simulation scheme) is a function of the current state. There are infact 3 different iteration schemes but I figured that an example with 2 is easier to explain.

(I'm not sure if it matters but I should probably also point out that in haskell the iterateByX functions are monadic since they use random numbers.)

2012-04-04 19:01
by Tom


1

A direct translation doesn't look too bad.

loop c x
    | stopCondition x = observe x
    | c > 0           = observe x >> iterateByA x >>= loop (c-1)
    | stepCondition x = observe x >> iterateByA x >>= loop 9
    | otherwise       = observe x >> iterateByB x >>= loop c

The repetition of observe can be removed via various tricks if you don't like it.

You should probably rethink things, though. This is a very imperative approach; probably something much better can be done (but it's hard to say how from the few details you've given here).

2012-04-04 19:31
by Daniel Wagner
Is this the same? The OP code calls observeState on the mutated version of x whereas your version calls observe on the pre-mutated version. Also the stopCondition case is tested at the end of the loop, not the start - pat 2012-04-04 20:14
@pat I wouldn't be at all surprised to find out there's an off-by-one error in my code. I hardly think that's the point, though - Daniel Wagner 2012-04-04 20:21
This actually doesn't look too bad, but as you say it is a very imperative approach. Ideally the stop condition and observation functions should be completely generic anyway, so theres not much to explain but I added a bit to the end anyway - Tom 2012-04-04 20:26
Ads