Hello John,

It is not really possible in normal Chuck syntax: functions are not values in Chuck and there is no function type.

However, you can simulate functions as values, by creating classes that create objects that behave like a function would.
The library LicK provides an implementation of that idea:
https://github.com/heuermh/lick/tree/master/lick/fn

The approach is best explained with an example I think.

// this is the Function class from LicK for functions that take one float argument.
class FloatFunction
{
    0.0 => float default;
    fun float evaluate(float arg0) // evaluate is abstract method applying the function to an argument. 
    {
        return default;
    }
}

// You extend it to make some function, for example, to make an addition Function object:
class Adder extends FloatFunction
{
    float value;
    
    fun void init(float arg) {
        arg => value;
    }
    
    fun float evaluate(float arg0) { // here we override the evaluate method from the base class.
        return value + arg0;
    }
}

// this is just a helper, to create a Adder object:
fun Adder mkAdder(float arg) {
    Adder a;
    a.init(arg);
    return a;
}

// Now it is possible to implement map, where you can take a function object as an argument:
fun float [] map (FloatFunction f, float lst[]) {
    float result[lst.cap()];
    for (int i;i<lst.cap();i++) {
        f.evaluate(lst[i]) => result[i];
    }
    return result;
}

fun void printArray(float arr[]) {
    for (int i;i<arr.cap();i++) {
        <<<arr[i]>>>;
    }
}

// so now your transposing mapping would look something like this:
[10.,11.,12.,13] @=> float test[];

map(mkAdder(10.0),test) => printArray;
map(mkAdder(20.0),test) => printArray;

A limitation that remains with this, since there is no curying etc.., you need a lot of classes, for each function type one. So creating and defining functions like this is not very lightweight (you almost always have to extend some class :-/). No surprise I guess: this is just programming a functional programming language using an object oriented one. My personal way of getting around that limitation was to build a translator in python that takes my own (scheme-like) syntax and parses it into chuck code* to automate all that boilerplate. But that is still quite a lot work! If you are really into doing functional stuff, it may also be worthwhile to consider use a “proper" functional language (ocaml/haskell) and communicate with chuck through OSC? It depends a bit on what level you would like to use the functions (controlling parameters or audio processing itself). I probably would have done something like this now if I didn’t have a whole bunch of tools written in chuck already :-P. 

Hope this helps,
Casper

* https://github.com/casperschipper/ChucK-Tools & https://github.com/casperschipper/cisp
There is some documentation in the cisp repo (sorry not very complete, this is kind of a personal toolbox).






On 25 Aug 2020, at 22:51, John Crane <john.crane@gmail.com> wrote:

Hi all, 

Chuck newbie here. Is it possible to pass a function as an argument? I'd like to be able to  transform things in a functional programming manner.  As a trivial example, if I had an array of midi notes and wanted to raise them all one interval. 

    fun int increment(int note) { 
        note + 1; 
    }

    // use map to apply a function to all elements of an array
    map ( array_of_notes, increment);

thanks in advance,

John
_______________________________________________
chuck-users mailing list
chuck-users@lists.cs.princeton.edu
https://lists.cs.princeton.edu/mailman/listinfo/chuck-users