首页 文章

C中的函数式编程有哪些工具?

提问于
浏览
137

我最近一直在思考如何在C(而不是C)中进行函数式编程 . 显然,C是一种过程语言,本身并不真正支持函数式编程 .

是否有任何编译器/语言扩展可以为语言添加一些函数式编程结构? GCC提供nested functions作为语言扩展;嵌套函数可以从父堆栈框架访问变量,但距离成熟的闭包还有很长的路要走 .

例如,我认为在C中真正有用的一件事是,在任何需要函数指针的地方,你都可以传递lambda表达式,创建一个衰变为函数指针的闭包 . C 0x将包括lambda表达式(我觉得很棒);但是,我正在寻找适用于直C的工具 .

[编辑]为了澄清,我不是试图解决C中更适合函数式编程的特定问题;如果我想这样做,我只是想知道那里有什么工具 .

13 回答

  • 0

    你可以使用GCC的嵌套函数来模拟lambda表达式,事实上,我有一个宏为我做这个:

    #define lambda(return_type, function_body) \
      ({ \
        return_type anon_func_name_ function_body \
        anon_func_name_; \
      })
    

    使用这样:

    int (*max)(int, int) = lambda (int, (int x, int y) { return x > y ? x : y; });
    
  • 1

    不知道C.目前在Objective-C中有一些功能特性,OSX上的GCC也支持一些功能,但我再次建议开始使用功能语言,上面提到了很多 . 我个人从计划开始,有一些优秀的书籍,如The Little Schemer,可以帮助你这样做 .

  • 4

    很多编程语言都是用C语言编写的 . 其中一些支持函数作为一等公民,该领域的语言是ecl(embbedabble common lisp IIRC),Gnu Smalltalk(gst)(Smalltalk有块),然后有库for "closures",例如glib2 http://library.gnome.org/devel/gobject/unstable/chapter-signal.html#closure,它至少接近函数式编程 . 因此,使用其中一些实现进行函数式编程可能是一种选择 .

    好吧,或者你可以去学习Ocaml,Haskell,Mozart / Oz等;-)

    问候

  • 48

    我在C中进行函数式编程的方法是在C中编写一个函数式语言解释器 . 我把它命名为Fexl,它是“Function EXpression Language”的缩写 .

    解释器非常小,在启用了-O3的系统上编译为68K . 它也不是玩具 - 我将它用于我为我的业务编写的所有新 生产环境 代码(基于网络的投资合伙企业会计 . )

    现在我只编写C代码(1)添加一个调用系统例程的内置函数(例如fork,exec,setrlimit等),或者(2)优化一个可以用Fexl编写的函数(例如搜索)对于子字符串) .

    模块机制基于“上下文”的概念 . 上下文是一个函数(用Fexl编写),它将符号映射到它的定义 . 当您阅读Fexl文件时,您可以使用您喜欢的任何上下文来解决它 . 这允许您创建自定义环境,或在受限制的“沙箱”中运行代码 .

    http://fexl.com

  • -5

    你想要实现功能,语法或语义的C是什么?函数式编程的语义当然可以添加到C编译器中,但是当你完成时,你基本上拥有现有函数语言之一,例如Scheme,Haskell等 .

    更好地利用时间来学习那些直接支持这些语义的语言的语法 .

  • 39

    如果你想实现闭包,你将不得不使用汇编语言和堆栈交换/管理 . 不推荐反对它,只是说这是你必须要做的 .

    不知道你将如何在C中处理匿名函数 . 在冯·诺依曼机器上,你可以在asm中执行匿名函数 .

  • 5

    函数式编程不是关于lambdas,而是关于纯函数 . 所以以下大致推广功能风格:

    • 仅使用函数参数,不使用全局状态 .

    • 尽量减少副作用,即printf或任何IO . 返回描述IO的数据,该IO可以执行而不是直接在所有函数中引起副作用 .

    这可以通过简单的c来实现,不需要魔法 .

  • 80

    函数式编程风格的先决条件是一流的功能 . 如果你容忍下一个,它可以在便携式C中模拟:

    • 词法范围绑定的手动管理,也就是闭包 .

    • 手动管理功能变量的生命周期 .

    • 函数应用程序/调用的替代语法 .

    /* 
     * with constraints desribed above we could have
     * good approximation of FP style in plain C
     */
    
    int increment_int(int x) {
      return x + 1;
    }
    
    WRAP_PLAIN_FUNCTION_TO_FIRST_CLASS(increment, increment_int);
    
    map(increment, list(number(0), number(1)); // --> list(1, 2)
    
    
    /* composition of first class function is also possible */
    
    function_t* computation = compose(
      increment,
      increment,
      increment
    );
    
    *(int*) call(computation, number(1)) == 4;
    

    此类代码的运行时可以小到下面的一个

    struct list_t {
      void* head;
      struct list_t* tail;
    };
    
    struct function_t {
       void* (*thunk)(list_t*);
       struct list_t* arguments;
    }
    
    void* apply(struct function_t* fn, struct list_t* arguments) {
      return fn->thunk(concat(fn->arguments, arguments));
    }
    
    /* expansion of WRAP_PLAIN_FUNCTION_TO_FIRST_CLASS */
    void* increment_thunk(struct list_t* arguments) {
      int x_arg = *(int*) arguments->head;
      int value = increment_int(x_arg);
      int* number = malloc(sizeof *number);
    
      return number ? (*number = value, number) : NULL;
    }
    
    struct function_t* increment = &(struct function_t) {
      increment_thunk,
      NULL
    };
    
    /* call(increment, number(1)) expands to */
    apply(increment, &(struct list_t) { number(1), NULL });
    

    本质上,我们模仿第一类函数,闭包表示为一对函数/参数加上一堆宏 . 完整的代码可以找到here .

  • 1
  • 6

    FFCALL允许您在C中构建闭包 - callback = alloc_callback(&function, data) 返回一个函数指针这样 callback(arg1, ...) 相当于调用 function(data, arg1, ...) . 但是,您必须手动处理垃圾回收 .

    相关地,blocks已被添加到Apple 's fork of GCC; they'不是函数指针,但它们允许您传递lambda,同时避免需要手动构建和释放捕获变量的存储空间(实际上,一些复制和引用计数发生,隐藏在一些语法糖之后)和运行时库) .

  • 17

    Felix language编译为C . 如果你不介意C,也许这可能是一块石头 .

  • 3

    想到的主要事情是使用代码生成器 . 您是否愿意使用提供函数式编程的不同语言进行编程,然后从中生成C代码?

    如果这不是一个有吸引力的选择,那么你可以滥用CPP来获得部分途径 . 宏系统应该让您模拟一些函数式编程思想 . 我听说过gcc是以这种方式实现的,但我从来没有检查过 .

    C当然可以使用函数指针传递函数,主要问题是缺少闭包,类型系统往往会妨碍 . 您可以探索比CPP更强大的宏系统,例如M4 . 我想最终,我建议的是,如果没有很大的努力,真正的C不能完成任务,但你可以扩展C以使其完成任务 . 如果您使用CPP,那么该扩展看起来最像C,或者您可以转到频谱的另一端并从其他语言生成C代码 .

  • -4

    Hartel&Muller的书,功能C,现在可以在(2012-01-02)找到:http://eprints.eemcs.utwente.nl/1077/(有PDF版本的链接) .

相关问题