簡體   English   中英

C中的高階函數作為一種語法糖,只需很少的努力

[英]Higher-order functions in C as a syntactic sugar with minimal effort

我想用C語言實現高階函數(HOF)作為語法糖,只需要很少的努力。 例如,對於以下代碼

function add(int x) {
  return int(int y) {
    return x + y;
  };
}

int main() {
  function add1 = add(1);
  return add1(2);
}

它被轉換成純C作為

#include <stdlib.h>

typedef struct {
  void *ctx;
  void* (*fun)(void *arg, void *ctx);
} function;

function new_function(void *ctx, void* (*fun)(void *, void *)) {
  function f = {.ctx=ctx, .fun=fun};
  return f;
}

void* apply(function f, void *arg) {
  return (*(f.fun))(arg, f.ctx);
}

typedef struct {
  int x;
} context$1;

void* new_context$1(int x) {
  context$1 *ctx = malloc(sizeof(context$1));
  ctx->x = x;
  return ctx;
}

void* function$1(void *arg, void *ctx) {
  int y = (int)arg;
  int x = ((context$1*)ctx)->x;
  return (void*)(x + y);
}

function add(int x) {
  return new_function(new_context$1(x), function$1);
}

int main() {
  function add1 = add(1);
  return (int)apply(add1, (void*)2);
}

我已經運行了這個(手動)轉換版本,它運行正常。 為了實現,我相信一些AST操作和lambda提升就足夠了。

我的方法有任何潛在的缺陷嗎? 是否有更簡單的HOF方法,或者我可以改進我的方法以使其更容易實現嗎?

現在有兩個明顯的問題:

  • 使用void *來表示任何類型的參數和返回值最終會中斷。 考慮ia-32上的“long long”參數,或者按值傳遞的任何結構。
  • 很難(如果可能的話)使高階函數在沒有垃圾收集的情況下有用。 您可以從自己的示例中看到它,其中上下文$ 1是malloc'ed但從未自由。 Boehm GC可能會有所幫助。

請注意,生成的代碼會調用未定義的行為。 在幾個地方,您通過直接轉換在整數類型和指針類型之間進行轉換。 這在C中是不合法的。您無法保證指針和int的大小相同,或者您甚至可以在它們之間進行轉換而不會更改或損壞該值。 代碼可能會巧合地在您的特定系統上運行,但它會在許多其他系統上中斷。

一般來說,只能處理指針和整數類型(以及結構)的唯一方法是使用可變長度參數列表傳遞參數。 這樣,無論基礎數據類型的大小如何,您都可以提取每個參數。

另一種選擇是刪除通用function結構,並為代碼中的每個HOF創建自定義結構。 然后,函數指針可以直接列出所有必需的參數,而不是嘗試在通用接口后面抽象它們,這將消除有問題的強制轉換,並允許代碼按預期工作,而不管使用的數據類型如何。

就可用性而言,考慮更改您的接口,以便在聲明它的行上指定(或至少列出 )HOF的返回類型。 C對象總是在聲明中列出它們的類型。 在您的示例中,聲明是function add1 = add(1); 要找出此函數返回的數據類型,您必須深入了解HOF的定義。 對於示例代碼而言,這不是一項艱巨的任務,但對於更復雜的代碼而言,這可能並非易事。 如果HOF來自圖書館,您可能根本沒有HOF的代碼。 也許像function(int) add1 = add(1); 可能更明確。

另外,我建議您將自動生成的函數定義為static以幫助防止模塊之間的名稱沖突。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM