(I understand that C is not intended to be used in a functional way. However, having learned functional programming, I have trouble thinking differently.)
Given those restrictions:
Can we think of a way of lifting a function f to take an extra parameter to fit a prototype, such as this new parameter will be ignored when f is executed?
Here is in detail what I want to do:
I want to fit a function f whose type is:
f :: void f(char *s)
in a function g that takes an function as an argument (call it arg), whose type is:
arg :: void f(unsigned int i, char *s)
Thus, the type of g is:
g :: void g(void (*f) (unsigned int, char))
The solution in haskell would be the following:
g (const f)
Is that even possible, maybe with some kind of macro wizardry?
EDIT: To provide a better understanding, here is the actual code. The body of ft_striter needs to be completed. The purpose is: apply the function f to every character of a string, using or not using its index i.
void ft_striter(char *s, void (*f) (char *s))
{
ft_striteri(?);
}
static void ft_striteri_helper(char *s, unsigned int i, void (*f)(unsigned int, char*))
{
if (*s)
{
f(i, s);
ft_striteri_helper(s + 1, i + 1, f);
}
}
void ft_striteri(char *s, void (*f)(unsigned int, char*))
{
ft_striteri_helper(s, 0, f);
}
You cannot implement this in standard portable C. The problem is that the function g
. is designed wrong. It should have type
void g(void (*f) (void *, unsigned int, char), void *ctxt)
and it should pass its ctxt
argument as the first argument to any f
calls it makes.
Now you can implement what you want with code like
struct const_ctxt {
void (*fun)(char *);
}
void const(void *ctxt, unsigned int i, char *s)
{
((struct const_ctxt *)ctxt)->fun(s);
}
void call_g_using_const_f(void (*f)(char *))
{
struct const_ctxt *ctxt = malloc(sizeof (struct const_ctxt));
ctxt->fun = f;
g(const, (void *)ctxt);
free(ctxt);
}
Warning: If the arguments to g
might escape the dynamic scope of g
then you will need to find another strategy for managing the allocation of the ctxt
s.
The pattern of g
taking a pair of a code pointer and a data "context"/"environment" pointer is how higher-level languages typically implement closures.
Since you want only to accept and ignore the extra parameter, you can accomplish this by creating a wrapper function with the required signature, that simply delegates to the original function:
void f2(unsigned int i, char *s) {
f(s);
}
With a proper declaration of that function in scope, you can then simply call
g(f2);
Function f2()
can be declared static if you wish, so that it is not visible to code outside the file in which it is defined. It does not need to be nested.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With