Count recursions

I have a code that approximates the solution in return, what it actually does is not important, but it works in the direction r '== rt, changing mg (suppose starting from 4.0, because I “know” that should be in the stadium).

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 do is count the number of cycles, I know that the right way to do this is with a state monad, but the most elegant way to put put / get in a function like this? Do f 'block lock? Or just add a solve_m 'counter and return (counter, mg)?

Thanks!

Edit: this seems to be basically what I want, and Monads are not needed:

 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) 

It still looks a bit dirty (re-code), but I will clean it up ... This gives me acceptable results in the 1 / 10000th iteration of the code that it will replace!

+4
source share
2 answers

Despite your algorithm, a general way to do this is to separate completion criteria from an iterative algorithm:

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

then use either iteration 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 expand:

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

EDIT: also note that these two intermediate elements are somewhat different in that the first supports the base register (input a , therefore, - 1 ), and the second does not, and therefore will have a slight difference in the additional resultAndRecursions .

+5
source

Well, firstly, you can remove most solve_m' arguments: they don't change in recursive calls, and solve_m arguments are in the where clause. This also makes the f' function unnecessary.

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

Now solve_m' is of type Double -> Double , because all it does is perform the next iteration, and then it either finishes or calls itself tail-recursively. As it happens, standard libraries include a function called iterate with type (a -> a) -> a -> [a] , which takes such a function and creates a (possibly endless) list of each step in the iteration. The number of recursive calls required is, of course, exactly the length of the resulting list. causes a confusing error in my answer.

In fact, iterate creates an endless list, in this case with endlessly repeating copies of the "final" result. Not exactly what you want. I was probably thinking of unfoldr :: (b -> Maybe (a, b)) -> b -> [a] .

Another option that I really prefer would be to remove a defender who checks that the answer is close enough, and use iterate in the end, creating an endless list of new approximations, and then destroy the resulting comparison list of adjacent elements to see how close you are. I would give sample code, but given an earlier error, which might be unreasonable.

EDIT: Well, for the sake of completeness, here are a few brief examples:

Using iterate and takeWhile :

 solve_m_iter f ar st qt = takeWhile notDoneYet $ iterate nextApprox 4.0 where rd mg = st + qt - f st ar mg notDoneYet mg = abs (rd mg) > precis nextApprox mg | rd mg > precis = mg - abs (rd mg) | rd mg < -precis = mg + abs (rd mg) 

Using unfoldr :

 solve_m_unfold f ar st qt = unfoldr nextApprox where nextApprox mg | rd > precis = keep $ mg - abs rd | rd < -precis = keep $ mg + abs rd | otherwise = Nothing where rd = st + qt - f st ar mg keep x = Just (x, x) 

And a slightly better function to get the result without double-checking the list:

 getResult = foldl (\(n, _) x -> (n + 1, x)) (0, 4.0) 

Definitely fast and dirty code, but hopefully useful.

+4
source

All Articles