Thanks, Peter! I applied the patch. I won't have time to create a proper test suite now, but I'll keep your instructions for the future.
Best wishes, Arthur On Fri, Apr 1, 2016 at 3:32 PM, Peter Bex <pe...@more-magic.net> wrote: > On Fri, Apr 01, 2016 at 03:28:26PM +0100, Andy Bennett wrote: > > Hi Peeps! > > > > I'm running CHICKEN 4.9.0rc1 and I'm trying out the memoize egg. > > > > I saw the tail-call-optimized version of the factorial procedure in the > > memoize documentation at http://api.call-cc.org/doc/memoize and I've > > been trying to modify it so that it memoizes intermediate results such > > that, for example, a call to (fact 10) makes a subsequent call to (fact > > 9) fast. > > > > Sometimes I'll crash immediately and someytimes I have to press some > > keys when the "#;8>" prompt appears. > > > > Is this a known bug in Chicken 4.9.0rc1 or the srfi-69 hash-tables that > > memoize uses? > > There are two problems. In your code you don't limit the size of the > memoized hash table, which means it won't ever delete anything from its > hash tables. > > The other problem seems to be in the memoize egg: there, even if you do > set a limit, the check for the hash table size occurs at precisely the > wrong place in the recursion. It checks the size, then calls the > procedure and when it returns, the result is stored in the hash table. > > Let's say we put a limit of 1. Then we call (memoized-fact 3). > It will determine (3) doesn't exist yet, and that the cache size is 0. > Then it will actually call (original-fact 3), which calls memoized-fact > recursively as (memoized-fact 2). In the recursion, the cache is still > empty and there's no entry for (2). So it calls (original-fact 2) to > determine the result to store. This calls (memoized-fact 1), which > enters with an empty cache and (1) doesn't exist yet. Then it calls > (original-fact 1), which returns with 1 immediately. > > When it returns, the result is stored in the hash table for args = (1). > This returns its value to the pending continuation which will > calculate 2, which is then stored in the cache for (2) and returned to > the pending continuation which will calculate our final result 6, which > is stored in the cache for (3) and then finally returned. > > After all this, the cache's size is 3 even though we capped it to a > limit of only 1 item! Also, the numbers you're storing _are_ really > large (the final result requires over 59KiB to store the number), and > because all the intermediate results are retained because the cache > isn't ever cleared, it's no wonder you're running out of heap size. > > The attached patch fixes the problem, as long as you do set a limit, > using (define memo-fact** (memoize fact** 10)). In fact, you can set > a limit of 1 if you want; the outermost recursion step is the one that > will never be deleted. > > A proper test suite should: > > a) ensure the procedure is only called as many times as necessary to > generate new values for uncached values. Fibonacci would be great > for measuring this: it should be called n times instead of n^2 times. > b) ensure that the cache limit is obeyed. This is trickier to write a > test for. Maybe something that is called in a sequence that looks > like 1, 1, 2, 2, 3, ... n, n, ... 3, 3, 2, 2, 1, 1 would be useful: > in that case it should be called exactly 2n times if the limit is < n, > unless I'm wrong. You'd then have to make a few variants of the > memoized procedure, with limits around the edge cases n, n-1, n+1 > and check if the original procedure is called 2n times or 4n times. > > I'm sure smarter people than myself can come up with a better way to > test this. > > Cheers, > Peter >
_______________________________________________ Chicken-users mailing list Chicken-users@nongnu.org https://lists.nongnu.org/mailman/listinfo/chicken-users