* : Beyond Currying

* : Beyond Currying

«* : Beyond Currying Jason Hemann Daniel P. Friedman Indiana University {jhemann,dfried}@cs.indiana.edu Abstract The Design Rationale states that Scheme is not prepared to Though the currying of functions has a long and storied his- deal with curried procedures in a convenient way and that tory, the technique has found less acceptance in Scheme than [t]he primary relevance of currying/uncurrying in Scheme one might at rst imagine. We present a function-creation is to teach concepts of combinatory logic [10]. We explore these arguments further in Section 2. mechanism λ∗ that, while maintaining the functionality of In this paper, we suggest that there may yet be a reason- Scheme's λ, provides enhanced features of function abstrac- tion and application, including automatic currying of func- able way to work with curried procedures in Scheme and tions, automatic nesting of applications, and reasonable be- that they may have some practical use. To do so, we develop havior when over- or under-supplied with arguments. systematically a mechanism for implicitly currying Scheme functions. This mechanism also provides partial application Categories and Subject Descriptors D.3.3 [Language of functions, consistent behavior for an excessive quantity of Constructs and Features]: Procedures, functions, and sub- arguments, and consistent behavior for variadic and nullary routines functions that we believe is consonant with such functions created with Scheme's . Keywords currying, partial application, macro, Scheme λ 2. Currying, curry, and $ 1. Introduction Currying began as a technique of mathematical logic, but The concept of currying functions is not new. The term has found use in programming. Although there are n! ways currying was coined by Christopher Strachey in 1967 for to curry an n argument function, here when we refer to cur- Haskell Curry who used it extensively [4, 23], though the rying we always mean currying from the left. Following the idea was known to Moses Schönnkel by at least 1920. In terminology of Moreno et. al [12], we describe the applica- his honor, the name schönnkeling has also been used [2]. tion of a curried function as partial, exact, or exceeding de- Quine, writing of Schönnkel's work [20], describes the pending whether the arguments provided to it are less than, concept thusly: equal to, or greater than the number of bindings in the list of All functions, propositional and otherwise, are for bindings in the uncurried form. Schönnkel one-place functions, thanks to the follow- We use the following conventions to describe function ing ingenious device (which was anticipated by Frege arity. Formals may be proper or improper. Proper formals denote functions of xed arity. Functions with the empty (1893, §36)). Where F is what we would ordinarily call a two-place function, Schönnkel reconstrues it formals list are called nullary. We use the term unary for functions of precisely one argument, and reserve polyadic by treating F xy not as F (x; y) but as (F x)y. Thus to mean functions of a xed arity at least two. We de- F becomes a one-place function whose value is a one-place function. The same trick applies to func- scribe those functions with a xed, positive arity (unary and polyadic functions collectively) as posary. A single variable tions of three or more places; thus F xyz is taken as or an improper list of formals denote functions of variable ((F x)y)z. arity. We call functions whose formals is a single symbol The technique is deeply rooted in category theory [1] variadic, and use the term polyvariadic to mean functions and is widely used in languages that support functions as of variable arity mandated to have at least one element. values. In both Haskell and ML, for instance, all functions This discussion of the ve non-overlapping formal param- are implicitly (automatically) curried. eter structures is summarized in Table 1. Currying is, however, not so ubiquitous in Scheme. The By always currying from the leftmost argument, curried documentation for SRFI-26, which provides operators for a functions provide, for free, partial application in the left form of partial application distinct from that possible with argument. Curried polyadic functions present opportunities traditional currying, suggests reasons this might be the case. to η-reduce that would have been otherwise impossible due Proper Improper (define-syntax $ nullary () variadic y (syntax-rules () ((_ f e) (f e)) unary (x) ∗ ∗ polyvariadic (x+. y) ((_ f e e :::) ($ (f e) e :::)))) polyadic (x+ y) Figure 2. A nested application macro, which passes each of Table 1. Formals of functions a list of arguments to a function until the list is exhausted. to arity mismatch. Where available, taking advantage of While code written using both curry and $ is more opportunities to η-reduce may make for shorter, clearer code. compact than with curry alone, it is unfortunate that we The verication of programs, either formally or informally, now require a macro for both abstraction and application. may also be aided by the code that currying can help create. ($ (curry (a b c d e) e) 1 2 3 4 5) A straightforward implementation of an explicit mecha- nism for currying functions in Scheme is of limited value Moreover, while this sufces as an implementation of though. currying in Scheme, this is far from ideal. For one, these mechanisms offer no support for nullary or variadic λs. Sec- ondly, the above example suggests that with this mechanism, (define-syntax curry currying is primarily useful only as part of a curry, special- (syntax-rules () ize, uncurry pattern: precisely the behavior SRFI-26 pro- ∗ ∗ ((_ (x . x ) e) (λ (x) ( curry x e))) vides, only more generally. ((_ ()e) e))) All of this seems to explain the discussions that took place Figure 1. A currying macro that takes a list of bindings and prior to ratication of SRFI-26, or at least shed more light returns nested functions of one binding each. on certain comments. From the above, one might indeed be led to conclude Scheme is not prepared to deal with The macro in Figure 1 takes as arguments a non-empty nested single-argument functions, and that, apart from the list of bindings and a body, akin to a subset of the func- curry, specialize, uncurry pattern, [c]urrying is pointless in Scheme [9]. tionality of Scheme's λ. This macro fails to function as one might hope when passed the empty list of bindings. Here, and for the remainder of this discussion, we presume valid 3. Development of * data, though the need for this assumption is diminished as « the discussion continues. It may be that the identied problems are not endemic to It transforms the expression into one with the same body, currying in Scheme per se, but perhaps just to particular im- but nested within unary λs in the number of bindings. This plementations. In this section we develop iteratively, through provides the ability to write functions as usual, but to ensure eight increasingly more general variants, a mechanism that that they now take arguments one at a time. This is similar meets the above objections. to a number of other implementations of currying [15, 18]. A mechanism for currying functions does not require The resultant functions must be invoked a single argument an operator like $. The λ∗ macro in Variant 1, with the at a time as in the following example, whose value is 5. associated function app∗ below, provides curried function denitions while allowing arguments to be passed as usual. ((((((curry (a b c d e) e) 1) 2) 3) 4) 5) Due to the highly parenthetical syntax of Lisp-like lan- (define-syntax λ∗ guages, currying in Scheme is typically viewed as somewhat (syntax-rules () inelegant. While in some instances it might be desirable to ((_ () e) e) pass arguments one at a time, it is often more readable and ((_ (x . x∗) e) ∗ ∗ ∗ ∗ ∗ more edifying to pass all arguments at once, or in a couple (λ (x . a ) (app (λ x e) a ))))) of distinct groupings. Passing arguments one at a time causes ( define app∗ the code to take up more room than it otherwise would. Too, (λ (f a∗) this verbosity may obscure understanding of the code's op- (if ( null? a∗) eration. f A nested application macro, here named $, relieves the (app∗ (f ( car a∗)) ( cdr a∗))))) burden of applying curried functions manually. The macro $ applies arguments one at a time to a chain of nested Variant 1: This denition of λ∗ uses app∗ which is recur- functions until the list of arguments is exhausted. As with sively dened over f and a∗. curry above, there are many implementations of $. This allows for the added exibility that comes with cur- > ((λ∗ (a b) (λ (d e) e)) 1 2 3 4) ried functions, while at the same time functions can be cre- exception ated and applied using the relatively more succinct syntax Worse, this denition of ∗ is aficted with a subtle, more of polyadic functions. From this follows short, exible code λ insidious aw: the code generated is not tail recursive. The and advantages that come with -reducing. η following is an example of a program that, with Scheme's ∗ is not, strictly speaking, actually currying the bind- λ λ loops indenitely, but when using ∗ instead consumes all ings. Instead, it returns a function which, when supplied a λ available memory. list of arguments, behaves as if it were curried. When sup- plied a list of bindings, which must be non-empty, the sec- > (letrec ((fn (λ∗ (x) (fn x)))) (fn 1)) ond clause is matched and λ∗ expands to a function expect- out of memory ing one or more arguments.

View Full Text

Details

  • File Type
    pdf
  • Upload Time
    -
  • Content Languages
    English
  • Upload User
    Anonymous/Not logged-in
  • File Pages
    7 Page
  • File Size
    -

Download

Channel Download Status
Express Download Enable

Copyright

We respect the copyrights and intellectual property rights of all users. All uploaded documents are either original works of the uploader or authorized works of the rightful owners.

  • Not to be reproduced or distributed without explicit permission.
  • Not used for commercial purposes outside of approved use cases.
  • Not used to infringe on the rights of the original creators.
  • If you believe any content infringes your copyright, please contact us immediately.

Support

For help with questions, suggestions, or problems, please contact us