Search code examples
cfunctionfunction-pointersfunction-composition

Defining and calling higher-order function composition functions with function pointers in C


The Wikipedia article on function types lists an interesting declaration of a "higher-order function composition function":

int (*compose(int (*f)(int), int (*g)(int)))(int);

As a learning exercise, I wanted to implement this in a test program, but failed, with the compiler throwing a number of warnings and errors. My attempt:

int a(int x) {
    return x + 1;
}

int b(int x) {
    return x * 2;
}

int (*compose(int (*f)(int y), int (*g)(int z)))(int x) {
    return (*f)(x) - (*g)(x);
}

int main(void) {
    int x = 5;
    int r = (*compose)((*a)(x), (*b)(x))(x);
    printf("Compose result for x = %d: %d\n", x, r);

    return 0;
}

I would be grateful for an explanation of how the declaration from Wikipedia differs from a simple function composition like f(g(h(x))) and how it may be implemented, preferrably with a simple program similar to mine.


Solution

  • Your compose function is declared to return a function pointer, but calculates and returns an int value instead.

    Also (*a)(x) calls the a function and you pass the int result to compose, instead of a pointer to the function a itself. Same with b.

    To solve your problem you first should call compose with pointers to the functions a and b:

    int r = (*compose(&a, &b))(x);
    

    Then you need to make compose return a pointer to a function, which includes creating the function to be returned:

    int (*f1)(int);
    int (*f2)(int);
    
    int compose_helper(int x)
    {
        return f1(x) - f2(x);
    }
    
    int (*compose(int (*f1_)(int), int (*f2_)(int)))(int)
    {
        f1 = f1_;
        f2 = f2_;
        return &compose_helper;
    }
    

    In C there's really no nice way of doing this, as function composition can't be done at run-time and there needs to be global state.


    As a side-note I really recommend that you create type-aliases for the function-pointers to make it all easier to read and understand.

    As in

    typedef int (fp_type)(int);
    
    fp_type *f1;
    fp_type *f2;
    
    fp_type *compose(fp_type *f1_, fp_type *f2_) { ... }