[chuck-users] Passing functions as arguments

Michael Heuer heuermh at gmail.com
Wed Aug 26 10:10:22 EDT 2020


Hello John, Casper

For better or worse, LiCK was inspired by functional-ish language features in Java (the colt library and commons-functor specifically) well before JDK8 lambdas or other JVM languages such as Scala.  The downside as Casper points out is lots of little classes.

John's original example might look like

IntArrayList notes;
notes.size(10);
notes.assign(42);
<<<notes.get(0)>>>;

class Increment extends IntFunction {
  fun int evaluate(int arg) {
    return arg + 1;
  }
}

Increment increment;
notes.transform(increment);
<<<notes.get(0)>>>;

...
[chuck](VM): sporking incoming shred: 1 (increment.ck)...
42 :(int)
43 :(int)


Hope this helps!

   michael


> On Aug 26, 2020, at 6:22 AM, Casper Schipper <casper.schipper at gmail.com> wrote:
> 
> 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 <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/ChucK-Tools> & https://github.com/casperschipper/cisp <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 at gmail.com <mailto:john.crane at 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 at lists.cs.princeton.edu <mailto:chuck-users at lists.cs.princeton.edu>
>> https://lists.cs.princeton.edu/mailman/listinfo/chuck-users
> 
> _______________________________________________
> chuck-users mailing list
> chuck-users at lists.cs.princeton.edu
> https://lists.cs.princeton.edu/mailman/listinfo/chuck-users

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.cs.princeton.edu/pipermail/chuck-users/attachments/20200826/bf5b4368/attachment-0001.html>


More information about the chuck-users mailing list