Documentation
Not logged in

Copyright (C) 2009-2010, Trevor Davel <twylite AT crypt DOT co DOT za>
See the file "LICENSE.txt" (Tcl/Tk License) for information on usage and redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.


TIP: Higher-order functions in Tcl

I am preparing a TIP based on the control::functional module.

Twylite 2010-04-02: This page is a summary of selected contributions made by many individuals to the Tclers Wiki and other Tcl-related projects, which I have massaged into a proposal that is hopefully broad in application and consistent with the features and practices of Tcl 8.6.

Contents

tl;dr

    set cmdprefix [list cmd arg1 arg2 ...]
 
    proc curry {func args} {
      # Conceptual implementation
      lappend func {*}$args
    }
    proc lambda {arglist body} {
      # Conceptual implementation
      set ns [uplevel 1 namespace current]
      list apply [list $arglist $body $ns]
    }

Ideas and related work

proc extensions as an alternative to lambda

Rather than define a new command lambda, we could extend proc to handle unnamed procs. NEM's proc replacement does exactly this, supporting anonymous functions and ensembles.

Better support for optional arguments

Partial application of arguments from the left (as in the proposed implementation of curry) points to a requirement to handle optional arguments towards the left end of the argument list. Tcl currently only supports optional and variadic arguments the the right of the argument list.

TIP #288 attempts to improve the situation with variadic arguments (args), but doesn't go far enough. control::range for example has arguments ?from? to ?step?, and the current implementation must use args and switch -- [llength $args] to produce the correct behaviour.

An argument assignment algorihtm that may provide a solution:

  1. "arglist" is the specified arguments to the proc.
  2. let i = 0.
  3. Scan arglist from the left, assigning to each non-optional argument the index [incr i].
  4. let minargs = i.
  5. Scan arglist from the left again, assigning to each optional argument (other than args) the index [incr i].
  6. let maxargs = i.
  7. if "args" is in the arglist then let maxargs = MAX_INT.
  8. "actualargs" is the list of arguments provided at the time the proc is called.
  9. if actualargs is shorter than minargs then ERROR.
  10. if actualargs is longer than maxargs then ERROR.
  11. for each argname in arglist: if ( length of actualargs >= index i of argname ) then assign the first element of actualargs to argname; else use the default value for argname.

What is attractive about this algorithm is that it is intuitive (for a left-to-right reader), handles optional and variadic args in any position in the arglist, and can be separated into preprocessing step that runs once with an efficient runtime step to assign the arguments.