Task

Pass a function     as an argument     to another function.



Related task

   First-class functions


include "cowgol.coh";
 
# In order to pass functions around, you must first define an interface.
# This is similar to a delegate in C#; it becomes a function pointer type.
# This interface takes two integers and returns one.
interface Dyadic(x: int32, y: int32): (r: int32);
 
# For a function to be able to be passed around, it must explicitly implement
# an interface. Then it has the same type as that interface.
# The interface replaces the method's parameter list entirely.
sub Add implements Dyadic is
    r := x + y;
end sub;
 
# Here are the other basic operators.
sub Sub implements Dyadic is r := x - y; end sub;
sub Mul implements Dyadic is r := x * y; end sub;
sub Div implements Dyadic is r := x / y; end sub;
 
# An interface is just like any other type, and the functions that implement
# it are first-class values. For example, this code maps the operator
# characters to their functions.
record Operator is
    char: uint8;
    func: Dyadic;
end record;
 
var operators: Operator[] := {
    {'+', Add}, {'-', Sub}, {'*', Mul}, {'/', Div},
    {0, Dyadic}
};
 
# This is a function that applies such a function to two values
sub apply(f: Dyadic, x: int32, y: int32): (r: int32) is
    r := f(x,y); # the function can be called as normal
end sub;
 
# And this is a function that applies all the above operators to two values
sub showAll(ops: [Operator], x: int32, y: int32) is 
    while ops.char != 0 loop
        print_i32(x as uint32);
        print_char(' ');
        print_char(ops.char);
        print_char(' ');
        print_i32(y as uint32);
        print(" = ");
        print_i32(apply(ops.func, x, y) as uint32);
        print_nl();
        ops := @next ops;
    end loop;
end sub;
 
showAll(&operators[0], 84, 42); # example