5.4.4  Mythryl Functions: List Handling Idioms

Let us return to the topic of functions which manipulate lists, and see how to write them in idiomatically correct Mythryl.

We have presented such functions previously in these tutorials, but they were written in a “C written in Mythryl syntax” style which would make any experienced Mythryl programmer wince.

Recall that the fundamental operator for constructing lists is the Mythryl ’!’ operator — what Lisp calls cons. By repeatedly using ’!’ to prepend values to the empty list, we can build up any valid Mythryl list:

    linux$ my

    eval:  "abc" ! [];

    eval:  "abc" ! ("def" ! []);
    ["abc", "def"]

    eval:  "abc" ! ("def" ! ("ghi" ! []));
    ["abc", "def", "ghi"]

Recall also that Mythryl functions allow pattern matching against arguments.

In fact, we now know that all the “argument lists” we have been using in our functions in the tutorials have really been extracting values from argument tuples via pattern matching. (I warned you that pattern matching keeps popping up in Mythryl where you least expect it!)

Put those two facts together with our new knowledge that Mythryl functions may accept arguments of any type — in particular, lists — and that Mythryl function syntax can encode implicit case statements, and we are now able to understand one of the list idioms dear to the Mythryl programmer’s heart:


    fun sum_list  list_of_integers
        sum_it (list_of_integers, 0)
            fun sum_it (    [], sum)  => sum;
                sum_it (i ! is, sum)  => sum_it( is, sum + i);

    printf "%d\n" (sum_list [1,2,3,4] );

Running the above will give you:

    linux$ ./my-script

The above is a list-processing idiom that you will see over and over again, and if you write any significant amount of real Mythryl code, you will write it over and over again.

Three points to note:

You will see this general pattern over and over again, until you can recognize it at a glance.

A frequent variation of it accumulates the result-so-far in a list. In this case, by the time we reach the terminating [] case on input, our result-so-far list is in the reverse order of of the original input list. We have been taking values from the front of the input list and adding them to the front of the result list, so in the end the first value processed, derived from the first element of the input list, is now at the end of the result list.

Consequently, the [] case will almost always reverse the result list before returning it:


    fun list_to_upper  list_of_strings
        f (list_of_strings, [])
            fun f (    [], results_so_far)  => reverse results_so_far;
                f (s ! ss, results_so_far)  => f( ss, (string::to_upper s) ! results_so_far);

    map  (printf "%s\n") (list_to_upper [ "abc", "def", "ghi" ] );

When run, the above produces

    linux$ ./my-script

Note how the reverse in the [] clause makes the results come out in the expected order.

Note also how the helper function is this time simply called f. I do not particularly approve of this idiom, but it is one you will see quite a bit in production Mythryl code, so it is good to get used to it. It certainly has the virtue of brevity.

Comments and suggestions to: