2

练习 1.41。定义一个过程 double,它将一个参数的过程作为参数,并返回一个应用原始过程两次的过程。例如,如果 inc 是一个对其参数加 1 的过程,那么(double inc)应该是一个加 2 的过程。返回什么值(((double (double double)) inc) 5)

我用 Python 实现了它。

def double(f):
    print(f)
    return (lambda x: (f(f(x))))

def inc(x):
    return x+1

print(double(inc)(0))
print((double(double))(inc)(0))
print((double(double(double)))(inc)(0)

输出:

<function inc at 0x00000000029BBB70>
2
<function double at 0x0000000002141730>
<function inc at 0x00000000029BBB70>
<function double.<locals>.<lambda> at 0x00000000029BBC80>
4
<function double at 0x0000000002141730>
<function double.<locals>.<lambda> at 0x00000000029BBD08>
<function inc at 0x00000000029BBB70>
<function double.<locals>.<lambda> at 0x00000000029BBBF8>
<function double.<locals>.<lambda> at 0x00000000029BBD90>
<function double.<locals>.<lambda> at 0x00000000029BBE18>
16

我的问题是:

  1. 为什么输出print((double(double(double)))(inc)(0)是 16 而不是 8?

  2. 为什么函数在运行时double被调用了 3 次而不是 2 次(double(double))(inc)(0)

  3. 是否有任何调试工具可以在 python 中设置断点,例如 C 中的“gdb”,以便我可以调试这个程序?

谢谢!

4

3 回答 3

3

让我们分析一下您的代码:

print( double(inc)(0) )

所以这将调用double带有参数的函数inc。因此,正如预期的那样,它将返回一个函数,该函数将inc在一个参数上应用该函数两次。所以你会得到 2 作为输出。你已经正确地做到了。

现在,有趣的一点在这里:

print( (double(double))(inc)(0) )

请注意,您已使用参数调用函数doubledouble然后使用参数调用生成的函数inc。所以这就是发生的事情:

  1. call double(double)# 即double带参数double(第一次调用double
  2. 你得到一个函数,它将double在参数上调用两次
  3. 你在inc.
  4. 所以你得到一个将应用double两次的函数inc(这里有两次调用double

你得到的是一个将增加 4 的函数。实际上这不是 2*2,而是 2^2,它只是巧合(或不是)2^2 = 2*2 = 4,所以你仍然得到答案4。

第三印:

print((double(double(double)))(inc)(0)

实际上,您调用double的结果double(double),它将对该函数double(double)本身应用两次。你打电话这么有效double(double)(double(double(inc)))。所以你应用函数inc2*2*(2*2) = 16 次。

为了更好地理解这一点,请注意:

print( double(double(double(inc)))(0) )

将打印 8。

于 2013-10-01T03:59:09.517 回答
2

正如其他人已经回答了要点一样,这里是您的代码的改进版本,它显示了具有描述性函数名称的执行流程:

def double(f):
    print('double({})'.format(f))
    def _f(x):
        print('{}({})'.format(_f.__name__, x))
        return f(f(x))
    _f.__name__ = 'double_{}'.format(f.__name__)
    return _f

def inc(x):
    return x + 1

print(double(inc)(0))
print((double(double))(inc)(0))
print((double(double(double)))(inc)(0))

输出:

double(<function inc at 0x7fb3a9ffa578>)
double_inc(0)
2
double(<function double at 0x7fb3a9ffa500>)
double_double(<function inc at 0x7fb3a9ffa578>)
double(<function inc at 0x7fb3a9ffa578>)
double(<function double_inc at 0x7fb3a9ffa6e0>)
double_double_inc(0)
double_inc(0)
double_inc(2)
4
double(<function double at 0x7fb3a9ffa500>)
double(<function double_double at 0x7fb3a9ffa7d0>)
double_double_double(<function inc at 0x7fb3a9ffa578>)
double_double(<function inc at 0x7fb3a9ffa578>)
double(<function inc at 0x7fb3a9ffa578>)
double(<function double_inc at 0x7fb3a9ffa8c0>)
double_double(<function double_double_inc at 0x7fb3a9ffa938>)
double(<function double_double_inc at 0x7fb3a9ffa938>)
double(<function double_double_double_inc at 0x7fb3a9ffa9b0>)
double_double_double_double_inc(0)
double_double_double_inc(0)
double_double_inc(0)
double_inc(0)
double_inc(2)
double_double_inc(4)
double_inc(4)
double_inc(6)
double_double_double_inc(8)
double_double_inc(8)
double_inc(8)
double_inc(10)
double_double_inc(12)
double_inc(12)
double_inc(14)
16
于 2013-10-01T04:03:26.413 回答
1
  1. double正如您清楚地指出的那样,将其论点应用于自身:

    lambda x: f(f(x))
    

    那是什么double(double(double))?一定是

    (double(double))(double(double))
    

    所以,16次。

  2. double(double)使用调用double来生产lambda f: double(double(f)). 将其应用于某些finc在这种情况下)需要两次调用double. 所以一共有三个。

  3. 我不知道是否gdb真的会帮助你。在这种情况下,铅笔和纸的 β 还原并不难,而且很可能更具启发性。

祝 SICP 好运!

于 2013-10-01T03:53:13.673 回答