方案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来说可能太晚了,我肯定作业几天前就要交了。我同时修复了它,把原来的功能完全隐藏了起来。