Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Counting the number of recursions

Tags:

haskell

I have some code that approximates a solution recusively, what it actually does is not important, but it works towards r' == rt by varying mg (m guess, starting with 4.0 because I "know" that ought to be in the ballpark).

solve_m f ar st qt = solve_m' f ar st qt 4.0
  where
    solve_m' f ar st qt mg 
      | rd > precis    = f' (mg - sf)  
      | rd < (-precis) = f' (mg + sf)  
      | otherwise = mg
        where 
          f' = solve_m' f ar st qt
          rt = st + qt   
          r' = f st ar mg 
          rd = rt - r'    
          sf = abs(rd) 

What I would like to be able to do is count the number of cycles, I know the right way to do this is with the State monad, but what is the most elegant way to fit the put/get into a function like this? Make f' a do block? Or is it simply to add a counter solve_m' and return (counter, mg)?

Thanks!

Edit: This seems to be basically what I want, and no Monads necessary:

solve_m f ar st qt = (last (series), length(series))
  where
  series = takeWhile termPred (iterate solve_m' 4.0)
  termPred m' = (abs (rt - (f st ar m'))) > precis
  rt = st + qt   
  solve_m' mg 
    | rt > r' = (mg - sf)  
    | rt < r' = (mg + sf)  
      where
        r' = f st ar mg 
        rd = rt - r' 
        sf = abs(rd)

Still looks a little messy (repeated code) but I'll tidy it up... This is getting me acceptable results in 1/10000th of the iterations of the code it will replace!

like image 904
Gaius Avatar asked Jan 22 '23 07:01

Gaius


1 Answers

Without looking at your algorithm, the generic way to do this is divide up your termination criteria from the iterative algorithm:

terminationPred :: a -> Bool
algorithm :: a -> a

then use either iterate and takeWhile:

itermediates = takeWhile (not . terminationPred) . iterate algorithm
resultAndRecursions :: a -> (a, Int)
resultAndRecursions a = (last (intermediates a), length (intermediates a) - 1)
-- you'd want to make your own safe function here, not use last and length

or unfold:

intermediates = unfoldr op
  where
  op a | terminationPred a = Nothing
       | otherwise = let a' = algorithm a
                     in Just (a', a')

EDIT: also notice these two intermediates are slightly different in that the first maintains the base case (the input a, hence the - 1) while the second does not and thus would have a minor difference in the complementary resultAndRecursions.

like image 192
Thomas M. DuBuisson Avatar answered Jan 23 '23 20:01

Thomas M. DuBuisson