方案lambda和所有程序运行

方案lambda和所有程序运行,lambda,scheme,r5rs,Lambda,Scheme,R5rs,当尝试运行这些过程时,在我调用之前,似乎一切都很好 (set! fib (mem 'memorize fib)) (fib 10) (fib 10) (set! fib (mem 'unmemorize fib)) (fib 4) 在我将“记忆”改为“不记忆”之后,发生的事情是,现在这两个词都被记住了 (define (mem mem-it func) (let ((table (make-table))) (case mem-it ((memoize)

当尝试运行这些过程时,在我调用之前,似乎一切都很好

 (set! fib (mem 'memorize fib))
 (fib 10)
 (fib 10)
 (set! fib (mem 'unmemorize fib))
 (fib 4)
在我将“记忆”改为“不记忆”之后,发生的事情是,现在这两个词都被记住了

(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")))))

我不明白当我调用'emomoize'时,它也会进入memoize=S

问题是,当你调用
(mem'emomoize fib)
时,你正在传递你在第一行中记忆的
fib

执行此操作[很抱歉,此“修复”错误]

(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")))))

好的,你已经诊断出问题了,下面是解决方案

任何已记忆的函数都会收到一些参数(否则我们就没有什么可记忆的了)。这意味着我们可以使用不带参数的调用来恢复原始函数:

(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"))))
格式为
(lambda args…body…
的lambda表达式在列表中收集其所有参数。例如:

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

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

正如Barmar在评论中正确指出的那样,对于具有可变参数数的函数,如果没有参数的调用是有意义的,那么这将不起作用。但对所有其他人来说,这都会起作用。但是,让它在所有情况下都起作用也是可能的。我们必须定义一个特殊符号,并用
eq?
检查它以触发恢复:

(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"))))))

这甚至在考虑参数之前就起作用了。

您需要做的是将原始定义保存到某个位置,以便在取消mozing时恢复它

(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")))))

您的
unemoize
代码不会删除任何备忘录。它返回的函数只调用它给定的函数,这是已经记忆的
fib
。啊哈。。。谢谢你澄清这一点,但现在它提出了更多的问题。更改的零件(删除lambda并添加原始func)。我做了您建议的更改,但没有任何更改,仍然存在相同的错误=/Ah,对。对不起,您必须实现它(我现在没有时间尝试)。但是,您理解最初的问题。我考虑实现的唯一方法实际上是使用lambda(args)从func传递参数。即使我在外部创建一个过程,我仍然需要调用fib和integer的func函数。如果函数的参数数量可变,则需要记住零参数调用返回的内容(例如,如果记住
+
,则应该记住
(+)
返回
0
)。所以你不能用它作为触发器。@Barmar好吧,对于像问题中的
fib
这样的“正常”函数,它可以正常工作。但我会再仔细考虑一下……他的原始代码只适用于一个参数函数,所以在这种情况下,您的解决方案是可行的。关于一般解决方案,请参见我的答案。但是对于OP来说可能太晚了,我肯定作业几天前就要交了。我同时修复了它,把原来的功能完全隐藏了起来。