[Richard Suchenwirth] 2002-01-21 - ''Currying'' (named after the founder of combinatory logic, Haskell Curry [http://www.cs.oberlin.edu/classes/dragn/labs/combinators/combinators11.html] - [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]...) ---- [escargo](?): Some references on currying: * [http://www.cs.nott.ac.uk/~gmh/faq.html#currying] * In Scheme [http://www.cs.oberlin.edu/classes/dragn/labs/combinators/combinators11.html], [http://www.engr.uconn.edu/~jeffm/Papers/curry.html]. * In Haskell [http://www.haskell.org/pipermail/haskell-cafe/2001-August/002087.html]. * In Perl6 [http://archive.develooper.com/perl6-language@perl.org/msg09950.html]. ---- One difference to "real curry" as in [Feather CurryObj] is that you have to pass in a name. It seems more functional to make up a name and return that, which would be identical to the call like used in [Lambda in Tcl]: proc curry2 args { set name [info level 0] eval [list interp alias {} $name {}] $args set name } ;# RS % set double2 [curry2 mult 2] ==> curry2 mult 2 % $double2 5 ==> 10 ---- [RS]: It appears as if currying is a special application of ''lambda'' (see [Lambda in Tcl]) and can also be implemented like this: set double3 [lambda x {mult 2 $x}] ==> lambda x {mult 2 $x} $double3 5 ==> 10 at the cost of one more level in call stack, so the ''[interp] alias'' solution appears to be gentler. ---- [SS] demonstrated in the [Tcl chatroom] on 2005-03-29 how to do curry with [Jim closures]: Curry in Jim: proc curry {cmd args} { lambda args [list cmd [list pref $args]] { uplevel 1 [list $cmd {expand}$pref {expand}$args] } } ---- '''Someone who speaks German could please fix the corrupted diacritics in this page?''' - this request will self-destruct in a few minutes ---- [Category Concept] | [Arts and crafts of Tcl-Tk programming] | [Category Functional Programming]