PreviousUpNext

10.9.4  Thunk Syntax

A function which takes only Void as an argument is often called a thunk. (Legend has it that the name comes from Algol 68, in which they were used to implement call-by-name, the explanation being that that the called routine didn’t have to think about the expression because the compiler had already "thunk" about it.)

Such functions are often used to encapsulate suspended computations which may be passed around or stored in datastructures and then later continued by invoking them with a void argument.

Thunks may be written easily enough using vanilla Mythryl anonymous function syntax:

    linux$ cat my-script
    #!/usr/bin/mythryl

    thunk =   \\ () = print "Done!\n";

    thunk ();

    linux$ ./my-script
    Done!

There are however times when even the above syntax can be annoying verbose; the fun () = prefix is visually distracting from the actual computation to be performed.

For such times Mythryl provides a special thunk notation, which looks just like a code block with a leading dot:

    linux$ cat my-script
    #!/usr/bin/mythryl

    thunk =   {. print "Done!\n"; };

    thunk ();

    linux$ ./my-script
    Done!

This syntax is entirely equivalent to the preceding anonymous function syntax, but is more compact and less distracting.

Mythryl thunk syntax does also support arguments.

Suppose for example that you wish to drop all nines from a list of integers. Package list provides a function list::filter which accepts a predicate function and a list and drops all list elements not satisfying the predicate function, which will do the job nicely:

    linux$ my

    eval: filter  (\\ a = a != 9)  [ 1, 9, 2, 4, 9, 9 ];

    [1, 2, 4]

The anonymous function syntax is however visually distracting here. Thunk syntax lets us do better:

    linux$ my

    eval:  filter  {. #a != 9; }  [ 1, 9, 2, 4, 9, 9 ];

    [1, 2, 4]

Here the # symbol marks the argument. This syntax is distinctly more readable than the vanilla anonymous function syntax.

Thunk syntax also supports multiple arguments, although in general if you need multiple arguments you should probably be writing a regular anonymous or named function. One nice application however is comparison function arguments to sort functions. For example the list_mergesort::sort function sorts a list according to a supplied comparison function. Suppose we wish to sort a list of strings by length:

    linux$ my

    eval:  list_mergesort::sort  (\\ (a, b) = strlen(a) > strlen(b))  [ "a", "def", "ab" ]; 

    ["a", "ab", "def"]

This works fine, but again the anonymous-function syntax is somewhat distracting. Thunk syntax is more concise and readable:

    linux$ my

    eval:  list_mergesort::sort  {. strlen(#a) > strlen(#b); }  [ "a", "def", "ab" ]; 

    ["a", "ab", "def"]

Thunk syntax is particularly useful when writing functions which are intended to mimic the functionality of compiler-implemented control structures:

    #!/usr/bin/mythryl

    foreach [ "abc", "def", "ghi" ] {.
        printf "%s\n" #word;
    };

    linux$ ./my-script
    abc
    def
    ghi

Here foreach is just a library function accepting two arguments:

    fun foreach []         thunk =>  ();
        foreach (a ! rest) thunk =>  { thunk(a);   foreach rest thunk; };
    end;

By using thunk syntax for the second argument we gain much of the compactness and convenience of a control construct built into the compiler.


Comments and suggestions to: bugs@mythryl.org

PreviousUpNext