手动执行函数体替换以查看过程如何工作 [英] Manually doing function body-substitution to see how a procedure works

查看:52
本文介绍了手动执行函数体替换以查看过程如何工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在逐步完成另一个答案中提供的程序 (https://stackoverflow.com/a/68013528/651174),我正在努力完成程序中的替换.这是我现在所处的位置:

I'm stepping through a procedure that was provided in another answer (https://stackoverflow.com/a/68013528/651174), and I'm struggling trying to finish the substitutions in the procedure. Here is where I'm at now:

; main function
(define (curry num func)
  (cond ((= num 1) func)
        (else (lambda (x) (curry (- num 1)
                                 (lambda args (apply func (cons x args))))))))

这是我正在打的电话:

(define (add-3 x y z) (+ x y z))
(add-3 100 200 300)
; 600
((((curry 3 add-3) 100) 200) 300)
; 600

这是我尝试通过代码替换来跟踪函数的工作原理:

Here is my attempt at substituting through the code to trace how the function works:

; Sub 1/3 (curry 3 add-3)
(lambda (x) (curry (- 3 1)
                   (lambda args (apply add-3 (cons x args)))))
; verify it works
((((lambda (x) (curry (- 3 1)
                   (lambda args (apply add-3 (cons x args))))) 100) 200) 300)
; 600 -- OK

; Sub 2/3 (curry 2 <func>)
; <func> = (lambda args (apply add-3 (cons x args)))
(lambda (x)
     (lambda (x) (curry (- 2 1)
                   (lambda args (apply (lambda args (apply add-3 (cons x args))) (cons x args))))))
; verify it works
((((lambda (x)
     (lambda (x) (curry (- 2 1)
                   (lambda args (apply (lambda args (apply add-3 (cons x args))) (cons x args)))))) 100) 200) 300)
; 700 -- Wrong output

我猜 700 值与我有两个 lambda (x) 并且没有正确封闭它们或其他东西有关.进行上述替换的正确方法是什么?

I am guessing the 700 value has to do with me having two lambda (x)'s and not properly enclosing them or something. What would be the proper way to do the above substitution?

推荐答案

一旦开始

((((lambda (x) (curry 2
                 (lambda args 
                   (apply add-3 (cons x args))))) 
   100) 200) 300)

您有两种选择可以继续.您可以尝试替换内部 curry,就像您在问题中所做的那样,但您必须小心避免引入另一个同名的变量,方法是重命名否则会发生冲突的新变量.因此,让我们使用 x1arg1 稍微更改一下您拥有的内容,以准备添加不同的数字:

you have two choices for how to proceed. You could try to substitute the inner curry, as you do in the question, but you have to be careful to avoid introducing another variable with the same name, by renaming new variables that would otherwise clash. So let's change what you have slightly, using x1 and arg1, in preparation for adding different numbers:

((((lambda (x1) (curry 2
                  (lambda args1 
                    (apply add-3 (cons x1 args1))))) 
   100) 200) 300)

现在展开内部的curry,就没有冲突了:

Now when you expand the inner curry, there is no conflict:

((((lambda (x1) 
     (lambda (x2)
       (curry 1 (lambda args2
                  (apply (lambda args1 
                           (apply add-3 (cons x1 args1)))
                         (cons x2 args2)))))) 
100) 200) 300)

请注意,这仍然会导致 600.当然,您可以轻松删除 (curry 1).从这里开始,您可以开始将这些 lambda 表达式的应用替换为参数 100、200 和 300.

Observe that this still results in 600. You can trivially remove the (curry 1), of course. From here, you could start substituting the applications of these lambdas to the arguments 100, 200, and 300.

但我认为走另一条路更简单.一旦您尝试计算的表达式是 ((lambda (x) ...) 100),不要深入研究 ...更复杂的 lambda.相反,将正文中的 x 替换为 100.这将使事情更具体一些,并且恰好与 Scheme 解释器实际评估表达式的方式相吻合.

But I think it's simpler to take the other road. Once the expression you're trying to evaluate is ((lambda (x) ...) 100), don't dive deeper into the ... to make a more complicated lambda. Instead, substitute 100 for x in the body. This will keep things a little more concrete, and happens to coincide with how a Scheme interpreter would actually evaluate the expression.

所以来自

((((lambda (x) (curry 2
                 (lambda args 
                   (apply add-3 (cons x args))))) 
   100) 200) 300)

我宁愿提前

(((curry 2
         (lambda args 
           (apply add-3 (cons 100 args))))
    200) 300)

现在当我们展开内部的 curry 时,没有冲突.(为了清楚起见,我使用名称 args1args2,但实际上它们的作用域并不冲突 - 您可以将它们都称为 args):

and now when we expand the inner curry there is no conflict. (I use names args1 and args2 for clarity, but they don't actually clash in scope - you could call them both args):

(((lambda (x)
    (curry 1
           (lambda args2
             (apply (lambda args1 
                      (apply add-3 (cons 100 args1)))
                    (cons x args2)))))
    200) 300)

f替换(curry 1 f),并用200替换x,留下

Replace (curry 1 f) with f, and substitute 200 for x, leaving

((lambda args2
   (apply (lambda args1 
            (apply add-3 (cons 100 args1)))
          (cons 200 args2)))
   300)

现在所有的 curry 都解决了,只剩下对 lambda 的 apply 调用.和以前一样,让我们​​解析最外层,用 args2 作为 list '(300):

Now all the currying is resolved, leaving just calls of apply on lambdas. As before let's resolve the outermost, with args2 as the list '(300):

(apply (lambda args1 
         (apply add-3 (cons 100 args1)))
       (cons 200 '(300)))
   
(apply (lambda args1 
         (apply add-3 (cons 100 args1)))
       '(200 300))

接下来在这个 lambda 上评估 apply,用 '(200 300) 代替 args1:

Next evaluate the apply on this lambda, substituting '(200 300) for args1:

(apply add-3 (cons 100 '(200 300)))

简化 cons 和最后一个 apply,我们只剩下我们希望找到的:

Simplify the cons, and the last apply, and we're left with what we hoped to find:

(add-3 100 200 300)

这篇关于手动执行函数体替换以查看过程如何工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆