Version 6 of Custom curry

Updated 2002-03-01 14:53:27

Richard Suchenwirth - Currying (named after the founder of combinatory logic, Haskell Curry [L1 ] - Playing Haskell) is in my understanding the act of deriving a function from another by adding one or more constant arguments. For instance, we can specialize the following general two-operand multiplier

 proc mult {a b} {expr $a*$b}

into a "doubler" that multipies its single argument by 2:

 proc double {a} {mult $a 2}

If all added arguments come before the "real" variables (in the last example, the order of the arguments can be swapped), we can easily use Tcl's interp alias command that does the same effect more efficiently, and saves one level in the call stack:

 interp alias {} double {} mult 2

(the {} indicating twice that the current interpreter is meant). Conversely, even without being aware, we have used currying whenever

  • a proc body consists of a single command with other args than of the proc
  • an interp alias has more than four arguments

We can use currying to factor out frequent calls or parts thereof, which might include assignment to a variable:

 interp alias {} -> {} set res
 -> 1 ;# equivalent to: set res 1

and of course we may curry the process of interp currying:}

 proc curry {new args} {eval [list interp alias {} $new {}] $args}

if 0 {Such custom currying may seem like obfuscation, but it makes for tighter code, as the following example, German plurals, shows. Repeated action like the adding of umlaut dots (a -> �) is factored out into a custom curry, as is the concatenation with a suffix (which otherwise would require frequent bracing of the variable name, as seen in English plurals:}

 proc sjoin args {join $args ""} ;# spaceless concat

 proc de:pl word {
    curry +   sjoin $word
    curry a:+ sjoin [string map {a �} $word]
    curry o:+ sjoin [string map {o �} $word]
    curry u:+ sjoin [string map {u �} $word]
    curry -1+ sjoin [string range $word 0 end-1]
    curry -2+ sjoin [string range $word 0 end-2]
    # The language inside the switch body looks strange, but clear:
    switch -- $word {
        Drucker - Fenster - Lehrer - L�ffel - Messer - Sch�ler
        - Hamster - Gitter - Finger - Schweinchen
           {+ ;# leave unchanged}
        Hund - Berg - Pferd - Krokodil - Tier - Problem - Bildschirm
        - Meer - Tisch - Begriff - Schaf - Haar - Kamel - Dromedar
        - Schwein
           {+ e}
        Bahn - Elefant - Frau - T�r - Zahl - Tastatur - Staat - Ohr
        - Burg
           {+ en}
        Kind - Rind - Bild - Schild - Geist - Brett
           {+ er}
        Katze - Frage - Pflanze - Stra�e - Gabel - Gasse - Diskette
        - Platte - Seite - Ratte - Kammer - Henne - See - Auge - Hase
           {+ n}
        Garten {a:+}
        Bach - Baum - Traum - Maus - Laus - Platz - Stadt - Kraft
        - Hand - Zaun
           {a:+ e}
        Haus - Mann - Tal {a:+ er}
        Kloster - Tochter - Vogel {o:+}
        Sohn - Hof - Wolf  {o:+ e}
        Dorf - Horn  {o:+ er}
        Mutter  {u:+}
        Fluss - Fu� - Kuh - Stuhl - Fuchs - Zug {u:+ e}
        Buch - Tuch - Huhn - Mund {u:+ er}
        Bus - Zirkus    {+ se}
        Thema   {-1+ en}
        Globus - Zyklus - Faktum - Medium - Museum {-2+ en}
        Kaktus  {-2+ een}
        Genus   {-2+ era}
        Modus   {-2+ i}
        Nomen - Pronomen {-2+ ina}
        Atlas   {-1+ nten}
        default {+ s}
    }
 }

Discussion: The "curry" names are defined directly before use, which increases readability. They are however never undefined and thus clutter the current interpreter. A cleaner solution would be to arrange for their destruction on leaving of this proc (see Local procedures for an analog example).

After marveling at the power of currying, and thinking further, it occurred to me that this is also possible in C by using macros:

 #define RES       res =
 #define DOUBLE(x) mult(x,2)

So, no big deal... or is it? You cannot pass these C macros as arguments (would raise syntax errors), while the Tcl curry examples above are callable by name, and thus can be further processed (e.g. with functional composition...)


Arts and crafts of Tcl-Tk programming