SICP练习1.41

时间:2013-10-01 03:26:56

标签: python algorithm debugging

  

练习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中设置断点的调试工具,如&#34; gdb&#34;在C中,我可以调试这个程序吗?

  4. 谢谢!

3 个答案:

答案 0 :(得分:2)

让我们分析您的代码:

print( double(inc)(0) )

因此,这将使用参数double调用函数inc。正如预期的那样,它将返回一个函数,该函数将在参数上应用函数inc两次。所以你将得到2作为输出。您已正确完成此操作。

现在,有趣的一点是:

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

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

  1. 拨打double(double)#即double,其中包含参数double(第一次拨打double
  2. 你得到一个函数,它会在参数
  3. 上调用double两次
  4. 您在inc上使用该功能。
  5. 因此您获得的功能会将double两次应用于inc(此处有double两次来电)
  6. 你得到的是一个增加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)))。因此,您应用函数inc 2 * 2 *(2 * 2)= 16次。

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

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

    将打印8。

答案 1 :(得分: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

答案 2 :(得分:1)

  1. double将其论证应用于自身,正如您明确指出:

    lambda x:f(f(x))

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

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

    所以,16次。

    SUCC(1)。 (是的,Markdown,2!2!2!2!)double(double)使用双倍调用来生成lambda f: double(double(f))。将其应用于某些f(在这种情况下为inc)需要两次调用double。所以总共有三个。

    SUCC(SUCC(1))。我不知道gdb是否真的在这里帮助过你。在这种情况下,铅笔和纸β-reduction并不困难,而且很可能更具启发性。

    祝SICP好运!