I'm using the following control structure(which I think is tail recursive)
untilSuccessOrBigError :: (Eq e) => (Integer -> (Either e a)) -> Integer -> e -> (Either e a)
untilSuccessOrBigError f count bigError
= case f count of
Right x -> Right x
Left e -> (if e==bigError then Left e else untilSuccessOrBigError f (count - 1) e)
to do iterative deepening
iterativeDeepening :: (a -> [a]) -> (a -> Bool) -> (a -> Bool) -> a -> Either String a
iterativeDeepening stepFunc isAValidSolution isGraphBottom x
= untilSuccessOrBigError
(\count -> dfsWithMaxDepth stepFunc isAValidSolution isGraphBottom count x)
(-1)
"Reached graph bottom"
will this free memory (since it will no longer technically be able to reach it) as at after each iterative deepening, if not how should I rewrite the control structure?
P.S. On second though it looks like this will fail since tail recursive structures frequently be able to access things on the stack like adding to the previous value, even if it doesn't in this case. – Roman A. Taycher Nov 28 at 12:33 P.P.S. On third though it makes me think that it can discard the values inside dfsWithMaxDepth as soon as dfsWithMaxDepth returns and a bunch of answers won't take up much memory. – 开发者_运维百科Roman A. Taycher Nov 2
At first glance, there's no reason that this won't be garbage collected properly, and why TCO won't be performed.
In general, you should think about tco and garbage collection in a different way in Haskell -- lots of related questions listed here on SO seem helpful. Fundamentally you want to imagine the operational semantics of GHC Haskell as lazy graph reduction.
Imagine that you just have the whole AST in memory, with additional arrows from every usage of a name to its definition, and you ask for the value of "main." Now to get that, you need to look at the value of the first function called in main, and substitute it in, which in turn means that you need to chase the next thing that needs to be evaluated, etc. Now at some point in this reduction, you'll notice that things that used to be pointed to as expressions have now been computed, and replaced with the values they represent. Then those expressions can get garbage collected. Meanwhile, the trace you've got from the top of the graph down to whatever piece you're now evaluating is the "stack". So if to evaluate a structure, you need to evaluate "inside" that structure, then that's going to grow your stack.
The above is sloppy and handwavy, but might help to give an intuition.
精彩评论