【问题标题】:Translating SICP solution from Scheme to Python将 SICP 解决方案从 Scheme 转换为 Python
【发布时间】:2013-10-24 19:31:30
【问题描述】:

我有这个 Lisp 中 SICP 代码的解决方案:

 ;; ex 1.11. Iterative implementation 

 (define (f n) 
   (define (iter a b c count) 
     (if (= count 0) 
       a 
       (iter b c (+ c (* 2 b) (* 3 a)) (- count 1)))) 
   (iter 0 1 2 n)) 

我真的不知道 Lisp 是如何工作的。我在这里理解了一些东西,但我仍然很难将它翻译成 Python。比如不知道a为什么写在if下面。这段代码如何翻译成 Python 或 C++? (函数必须是迭代的而不是递归的)

【问题讨论】:

标签: python lisp scheme sicp


【解决方案1】:

有两种方法可以考虑翻译。一种方法是在不尊重 Python 的习惯用法和约定的情况下编写一个字面的、直接的翻译——它看起来像这样:

def f(n):
    def iter(a, b, c, count):
        if count == 0:
            return a
        else:
            return iter(b, c, 2*b + 3*a + c, count-1)
    return iter(0, 1, 2, n)

另一种方法是以 Python 风格编写代码,以尊重目标语言的约定并利用其迭代机制:

def f(n):
    a, b, c = 0, 1, 2
    for count in range(n):
        a, b, c = b, c, 2*b + 3*a + c
    return a

顺便说一下,第二个版本会更快,并且不会出现堆栈溢出错误的问题(Python 没有针对递归进行了优化!)。在递归版本中countn0 和在循环版本中count0n 是无关紧要的,因为无论如何count 的值都没有用于除了迭代给定次数之外的任何东西。

【讨论】:

    【解决方案2】:

    让我们看一下这段代码:

    ;; ex 1.11. Iterative implementation 
    
    (define (f n) 
      (define (iter a b c count) 
        (if (= count 0) 
          a 
          (iter b c (+ c (* 2 b) (* 3 a)) (- count 1)))) 
      (iter 0 1 2 n)) 
    

    首先要注意的是定义了两个函数。一个是f,另一个是iteriter 是一个辅助函数,仅供f 使用(因为它是在finside 中定义的。没有理由不能将这两个定义分开,不过,进入:

    (define (iter a b c count) 
      (if (= count 0) 
        a 
        (iter b c (+ c (* 2 b) (* 3 a)) (- count 1))))
    
    (define (f n) 
      (iter 0 1 2 n)) 
    

    在 Lisps 中,语法 (frob bar1 bar2 ...) 表示您正在使用参数 bar1bar2... 调用函数 frob。所以f的定义

    (define (f n) 
      (iter 0 1 2 n)) 
    

    应该比较清楚。你定义了一个函数f,它接受一个参数n,然后你用四个参数调用函数iter012n。那么iter 是做什么的呢?

    (define (iter a b c count) 
      (if (= count 0) 
        a 
        (iter b c (+ c (* 2 b) (* 3 a)) (- count 1))))
    

    iter 接受四个参数。首先,它检查count 是否为0。如果是,则iter 返回a。否则,iter 会使用bc 递归调用自身。 (+ c (* 2 b) (* 3 a))(- count 1) 以及递归调用返回的值被返回。根据上面对 Lisp 语法的描述,你应该可以看出 (+ c (* 2 b) (* 3 a)) 只是数学表达式 c + 2b + 3a,而 (- count 1) 只是 count-1 .

    我想,关于这一切的最棘手的部分是知道if 接受三个参数:第一个是测试表达式;第二个是“then”部分,也称为consequent;第三个是“else”部分,也称为alternative。与 if 仅用于有条件地执行某些语句的其他一些语言不同,(if ...) 在 Lisp 中返回一个 ,该值要么是结果的值,要么是替代的值,取决于测试的值是真还是假。

    有了这个描述,你应该可以用你熟悉的任何编程语言写出对应的东西。

    当然,一旦你理解了所有这些,你最好阅读一些Chris Rathman's translation of SICP code into Python,其中包括练习1.11中代码的翻译:

    # Exercise 1.11
    def f(n):
       if n < 3:
          return n
       else:
          return f(n-1) + 2*f(n-2) + 3*f(n-3)
    def f_iter(a, b, c, count):
       if count == 0:
          return c
       else:
          return f_iter(a + 2*b + 3*c, a, b, count-1)
    def f(n):
       return f_iter(2, 1, 0, n)
    

    【讨论】:

      【解决方案3】:

      这基本上是iter在C中的样子

      int iter (int a, int b, int c, int count)
      {
          if( count == 0 )
             return a;
          else
             return iter(b, c, c + (2 * b) + (3 * a), count - 1);
      }
      

      Scheme 中的每个表达式都会计算一个值,因此它是隐式返回。 if 返回分支运行的任何内容,iter 返回 if 返回的内容,依此类推。

      在不确定的情况下,这看起来像是一个递归序列,它引用前 3 个数字来计算下一个数字,该数字已在 Scheme 中迭代到常量堆栈。请注意,Python 不会尾部调用对此进行优化,而 C++ 和 C 可能需要特殊的编译器选项和有能力的编译器来做到这一点。

      【讨论】:

      • 或基于while 的显式循环重写。 :)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-06-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多