美文网首页
Scheme、C 中的过程作为参数

Scheme、C 中的过程作为参数

作者: LunaElf | 来源:发表于2020-02-23 09:32 被阅读0次

    过程(C 中称为函数,其实是同一个东西)作为参数,是一种建立抽象的手段。它极大地增强了语言的表达能力。我们可以使用这种方式简化代码。

    Scheme

    在 Scheme 中,可以直接把过程作为参数传递给过程,就像把数据传递给过程一样。

    (define (cube x) (* x x x)) ;; 定义一个过程 cube,x 是参数,计算 x 的立方
    (define (add f a b) ;; 定义一个过程 add,f、a、b 是三个参数,计算 (f a)+(f b) 的值,f 代表一个过程
      (+ (f a) (f b)))
    

    接下来举一个例子,看看过程作为参数的强大之处。例子取自 SICP

    考虑下面的三个过程,第一个计算从 a 到 b 的各整数之和。例如,1 + 2 + 3 +...

    (define (sum-integers a b)
      (if (> a b)
          0
          (+ a (sum-integers (+ a 1) b)))) ;; 递归调用
    

    第二个计算给定范围内的整数的立方之和。例如,1^3 + 2^3 + 3^3 +...

    (define (sum-cubes a b)
      (if (> a b)
          0
          (+ cube a) (sum-cubes (+ a 1) b))))
    

    第三个计算类似下面的序列之和:1/(1*3) + 1/(5*7) + 1/(9*11) +...

    (define (pi-sum a b)
      (if (> a b)
          0
          (+ (/ 1.0 (* a (+ a 2))) (pi-sum (+ a 4) b))))
    

    这三个过程存在着一种公共的模式,数学家称之为“求和记法”。我们可以通过过程作为参数把这种模式表示出来。

    (define (sum term a next b) ;; term 和 next 是过程
      (if (> a b)
          0
          (+ (term a) ;; 调用 term
             (sum term (next a) next b)))) ;; 调用 next
    

    利用sum过程重新构造上面三个计算。

    (define (inc n) (+ n 1))
    
    ;; 第一个计算
    (define (sum-integers a b)
      (define (identity x) x) ;; 定义一个内部过程
      (sum identity a inc b)) ;; 过程定义。调用 sum
    
    ;; 第二个计算
    (define (sum-cubes a b)
      (sum cube a inc b))
    
    ;; 第三个计算
    (define (pi-sum a b)
      (define (pi-term x)
        (/ 1.0 (* x (+ x 2))))
      (define (pi-next x)
        (+ x 4))
      (sum pi-term a pi-next b))
    

    一旦有了 sum,我们就能用它做为基本构件,去形式化其他概念。

    C

    C 中的过程作为参数,可以用函数指针来实现。函数指针,即指向函数的指针。

    int add(int a, int b) { // 定义一个函数
        return a + b;
    }
    
    int sub(int a, int b) { // 参数、返回值跟 add 函数相同
        return a - b;
    }
    
    // 使用函数指针
    int use_func(int (*func)(int, int), int a, int b) {
        return (*func)(a, b);
    }
    

    int (*func)(int, int) 是函数指针定义,它放在 use_func 函数的参数表里,表明这个参数接受一个函数名做为参数,但是这个函数名所表示的函数需要两个 int 参数,返回值为 int。有了上述函数定义之后,我们可以在 main 函数中使用。

    int main(void) {
        printf("%d\n", use_func(add, 1, 2)); // 3
        printf("%d\n", use_func(sub, 3, 4)); // -1
        return 0;
    }
    

    有了上面的基础,接下来定义 C 中的 sum 函数。上面第一个和第二个计算返回值的数据类型是 int,第三个计算返回值的数据类型是 double。为了代码的简洁,这里不使用泛型,统一为 double

    double sum(double (*term)(int), int a, int (*next)(int), int b) { // 有两个函数指针,term 和 next
        if (a > b) {
            return 0;
        } else {
            return (*term)(a) + sum(term, (*next)(a), next, b); // 调用 term 和 next
        }
    }
    

    sum 去构造前面三个计算。

    // 第一个计算
    double sum_integers(int a, int b) {
        return sum(identity, a, inc, b); // 调用 sum
    }
    
    // 第二个计算
    double sum_cubes(int a, int b) {
        return sum(cube, a, inc, b);
    }
    
    // 第三个计算
    double pi_sum(int a, int b) {
        return sum(pi_term, a, pi_next, b);
    }
    
    double identity(int x) {
        return x;
    }
    
    double cube(int x) {
        return x * x * x;
    }
    
    double pi_term(int x) {
        return 1.0 / (x * (x + 2));
    }
    
    int inc(int x) {
        return x + 1;
    }
    
    int pi_next(int x) {
        return x + 4;
    }
    

    最后,在 main 函数中测试一下。

    int main(void) {
        printf("%lf\n", sum_integers(1, 10)); // 55.000000
        printf("%lf\n", sum_cubes(1, 10)); // 3025.000000
        printf("%lf\n", pi_sum(1, 1000) * 8); // 计算 pi 的近似值。3.139593
        return 0;
    }
    

    通过 Scheme 和 C 的比较,我们可以看到 Scheme 支持在过程中定义过程,而 C 不支持在函数中定义函数。

    相关文章

      网友评论

          本文标题:Scheme、C 中的过程作为参数

          本文链接:https://www.haomeiwen.com/subject/spmdqhtx.html