0

When trying to run these procedures, it seems everything is fine until I call

 (set! fib (mem 'memorize fib))
 (fib 10)
 (fib 10)
 (set! fib (mem 'unmemorize fib))
 (fib 4)

What happens is after I changed 'memorize TO 'unmemorize is that it does them both now

(define (mem mem-it func)
  (let ((table (make-table)))
    (case mem-it
      ((memoize)
       (display " --- memoize ---\n")
       (lambda (args)
         (let ((prev-com-res (lookup args table))) ;; prev-com-res = previously-computed-result
           (display " --- memoize2 ---\n")
           (or prev-com-res                            
               (let ((result (func args)))                  
                 (insert! args result table)
                 result)))))
      ((unmemoize)
       (display " --- unmemoize --- \n")
       (lambda (args)
         (let ((comp (func args)))
           comp)))
      (else
       (display " -- Unknown command! --\n")))))

I don't understand when I'm calling on 'unmemoize, it goes into the memoize too =S

  • Your `unmemoize` code doesn't remove any memoization. The function it returns just calls the function it was given, which is the already-memoized `fib`. – Barmar Apr 25 '13 at 19:04

3 Answers3

1

The problem is that when you call (mem 'unmemoize fib) you are passing fib which you memoized in your first line!

Do this [Sorry this 'fix' is wrong]

(define (mem mem-it func)
  (let ((table (make-table))
        (original-func func))     ;; added
    (case mem-it
      ((memoize)
       (display " --- memoize ---\n")
       (lambda (args)
         (let ((prev-com-res (lookup args table))) ;; prev-com-res = previously-computed-result
           (display " --- memoize2 ---\n")
           (or prev-com-res                            
               (let ((result (func args)))                  
                 (insert! args result table)
                 result)))))
      ((unmemoize)
       (display " --- unmemoize --- \n")
       original-func)                   ;; changed
      (else
       (display " -- Unknown command! --\n")))))
GoZoner
  • 67,920
  • 20
  • 95
  • 145
  • aha... thanks for clearing that up =D but now it raises more questions. The part you changed(removed lambda and added original-func). I made the changes you suggested, but nothing has changed, the same error is still there =/ – user2079185 Apr 25 '13 at 19:25
  • Ah, right. Sorry, you'll have to implement it (no time at the moment for me to try). But, you understand the original issue. – GoZoner Apr 25 '13 at 19:41
  • The only way I can think about an implementation is actually using the lambda (args) to pass arguments from the func. Even when I'm creating a procedure outside, I still need to call the func wich is fib and an integer – user2079185 Apr 25 '13 at 20:42
0

OK, so you've got the problem diagnosed already, here's the solution.

Any memoized function receives some arguments (or else we'd have nothing to memoize it on). That means that the call without arguments is available to us, to recover the original function:

(define (mem mem-it func)
    (case mem-it
      ((memoize)
       (display " --- memoize ---\n")
       (let ((table (make-table)))                 ;; changed
        (lambda args   (if (null? args) func       ;; changed 
         (let ((prev-com-res (lookup args table))) 
           (display " --- memoize2 ---\n")
           (or prev-com-res                            
               (let ((result (apply func args)))   ;; changed             
                 (insert! args result table)
                 result)))))))                     ;; changed
      ((unmemoize)
       (display " --- unmemoize --- \n")
       (func))                                     ;; changed 
      (else
       (display " -- Unknown command! --\n"))))

A lambda-expression of the form (lambda args ...body...) collects all its arguments in a list. E.g.:

(define qq (lambda args args))
;Value: qq

(qq 1 2 3)
;Value 12: (1 2 3)

as Barmar correctly points out in the comments, this won't work for functions with variable number of arguments for which a call with no arguments is meaningful. But for all others, it will work. But, to make it work in all cases, is also possible. We'll have to define a special symbol, and check it with eq? to trigger the recovery:

(define mem
 (let ((trigger (list 'trigger))                
       (check   (list 'check))) 
  (lambda (mem-it func)                               ;; changed
    (case mem-it
      ((memoize)
       (display " --- memoize ---\n")
       (let ((table (make-table)))                    ;; changed
        (lambda args   (if (eq? check trigger) func   ;; changed 
         (let ((prev-com-res (lookup args table))) 
           (display " --- memoize2 ---\n")
           (or prev-com-res                            
               (let ((result (apply func args)))      ;; changed 
                 (insert! args result table)
                 result)))))))                        ;; changed
      ((unmemoize)
       (display " --- unmemoize --- \n")
       (let ((c check))                            ;; changed...
         (set! check trigger)  ;; or: (fluid-let ((check trigger))
         (let ((f (func)))     ;;       (func))
           (set! check c)
           f)))                                    ;; ...changed
      (else
       (display " -- Unknown command! --\n"))))))

This works even before the arguments are considered.

Will Ness
  • 70,110
  • 9
  • 98
  • 181
  • If the function takes variable number of arguments, you need to memoize what the zero-argument call returns (e.g. if you memoize `+`, it should remember that `(+)` returns `0`). So you can't use that as a trigger. – Barmar May 01 '13 at 16:00
  • @Barmar well, for "normal" functions like `fib` in the question it will work OK. but will think this over some more... – Will Ness May 01 '13 at 16:01
  • His original code only worked for one-argument functions anyway, so your solution would work in that case. See my answer for the general solution. But it's probably too late for the OP, I'm sure the homework assignment was due several days ago. – Barmar May 01 '13 at 16:09
0

What you have to do is save the original definition somewhere, so you can restore it when unmemoizing.

(define *original-functions* (make-table))

(define (mem mem-it func)
  (let ((table (make-table))
        (original-func func))     ;; added
    (case mem-it
      ((memoize)
       (display " --- memoize ---\n")
       (let ((new-func
              (lambda args
                (let ((prev-com-res (lookup args table))) ;; prev-com-res = previously-computed-result
                  (display " --- memoize2 ---\n")
                  (or prev-com-res                            
                      (let ((result (apply func args)))                  
                        (insert! args result table)
                        result))))))
         (insert! new-func original-func *original-functions*)
         new-func))
      ((unmemoize)
       (display " --- unmemoize --- \n")
       (lookup func *original-functions*))
      (else
       (display " -- Unknown command! --\n")))))
Barmar
  • 741,623
  • 53
  • 500
  • 612