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.