【在主画面加入捷径】
       
【选择语系】
繁中 简中

[C 语言] 程序设计教学:撰写函数式程序 (Functional Programming)

【赞助商连结】

    函数式程序由函式组成程序,具有主流程序较少见到的特性,像是尽量避免状态改变、把函式当成值来使用等。C 语言不是函数式语言,但仍有少数函数式程序的特性。本文中介绍一些在 C 语言中可见的函数式程序特性,这些写法不是主流的手法,故仅供参考。

    闭包 (Closure)

    C 语言没有真正的闭包,但透过静态局部变量 (static local variable) 可以仿真有状态的函式 (stateful function),即闭包 (closure)。例如以下用来生成质数 (prime number) 的函式:

    unsigned prime(void)
    {
        static unsigned n = 1;
    
        while (true) {
            n += 1;
            bool is_prime = true;
            
            unsigned i = 2;
            while (i < sqrt(n)) {
                if (n % 2 == 0) {
                    is_prime = false;
                    break;
                }
            
                i += 1;
            }
            
            if (is_prime)
                goto END;
        }
        
    END:
        return n;
    }

    承上,可用此函式求小于等于 100 的质数:

    unsigned n;
    while ((n = prime()) <= 100)
        printf("%u\n", n);

    这个手法可行的原因在于静态局部变量的状态在每次函式调用后会保留下来,下次函式调用时会从先前的状态恢复,行为上很像闭包。但在多线程程序中,使用静态局部变量问题较多,故这个写法仅供参考。

    匿名函式 (Anonymous Function)

    标准 C 缺乏匿名函式 (anonymous function) 的特性,以下范例使用 GCC 的延伸功能来实现匿名函式:

    #include <assert.h>
    
    // Generic lambda function
    #define lambda(type, body) ({ \
            type __fn__ body; \
            __fn__; \
        })
    
    int main(void) {
        assert(lambda(int, (int a , int b) { 
            return a > b ? a : b;
        })(3, 5) == 5);
    
        return 0;
    }

    由于这不是标准 C 语言的特性,即使 GCC 很常见,也应该慎重使用。这个写法仅供参考,不用刻意使用这种手法。

    高阶函式 (Higher-Order Function)

    高阶函式 (higher-order function) 是使用函式为参数或回传值的函式。例如,以下的 list_select函数仅保留串行中符合 filter 条件的元素:

    typedef bool (*filterFn) (int);
    
    bool list_select_mut(List **self, filterFn filter)
    {
        assert(*self);
    
        List *out = list_new();
        if (!out) {
            return false;
        }
    
        Node *curr = (*self)->head;
        while (curr) {
            if (filter(curr->data)) {
                if (!list_push(out, curr->data)) {
                    list_free(out);
    
                    return false;
                }
            }
    
            curr = curr->next;
        }
    
        list_free(*self);
        *self = out;
    
        return true;
    }

    在这个函式中,filter 接收一个函式常参数,所以 list_select_mut 是高阶函式。但这个范例没有考虑多线程的情境,只是逐一走访串行物件 self 的元素,故仅供参考。

    【赞助商连结】