Keyword and Optional Arguments in PLT Scheme
Total Page:16
File Type:pdf, Size:1020Kb
Keyword and Optional Arguments in PLT Scheme Matthew Flatt Eli Barzilay University of Utah and PLT Northeastern University and PLT mfl[email protected] [email protected] Abstract (define rectangle The lambda and procedure-application forms in PLT Scheme sup- (lambda (width height #:color color) port arguments that are tagged with keywords, instead of identified ....)) by position, as well as optional arguments with default values. Un- or like previous keyword-argument systems for Scheme, a keyword is not self-quoting as an expression, and keyword arguments use (define (rectangle width height #:color color) ....) a different calling convention than non-keyword arguments. Con- sequently, a keyword serves more reliably (e.g., in terms of error This rectangle procedure could be called as reporting) as a lightweight syntactic delimiter on procedure argu- (rectangle 10 20 #:color "blue") ments. Our design requires no changes to the PLT Scheme core compiler, because lambda and application forms that support key- A keyword argument can be in any position relative to other argu- words are implemented by macros over conventional core forms ments, so the following two calls are equivalent to the preceding that lack keyword support. one: (rectangle #:color "blue" 10 20) 1. Using Keyword and Optional Arguments (rectangle 10 #:color "blue" 20) The #:color formal argument could have been in any position A rich programming language offers many ways to abstract and among the arguments in the definition of rectangle, as well. In parameterize code. In Scheme, first-class procedures are the pri- general, keyword arguments are designed to look the same in both mary means of abstraction, and procedures are unquestionably the the declaration and application of a procedure. right vehicle for parameterizing code with respect to a few run-time In a procedure declaration, a formal argument can be paired values. For parameterization over larger sets of values, however, with a default-value expression using a set of parentheses—or, Scheme procedures quickly become inconvenient. by convention, square brackets. The notation for a default-value Keyword and optional arguments support tasks that need more expression is the same whether the argument is by-position or by- arguments than fit comfortably into procedures, but where radia- keyword. For example, a rectangle’s height might default to its cally different forms—such as unit or class in PLT Scheme— width and its color default to pink: are too heavyweight conceptually and notationally. At the same time, keyword and optional arguments offer a smooth extension (define (rectangle width path for existing procedure-based APIs. Keyword arguments can [height width] be added to a procedure to extend its functionality without bind- #:color [color "pink"]) ing a new identifier (which always carries the danger of colliding ....) with other bindings) and in a way that composes with other such This revised rectangle procedure could be called in any of the extensions. following ways: Keyword arguments in PLT Scheme are supported through a (rectangle 10) straightforward extension of the lambda, define, and applica- (rectangle 10 20) tion forms. Lexically, a keyword starts with #: and continues in the (rectangle 10 20 #:color "blue") same way as an identifier; for example, #:color is a keyword.1 (rectangle 10 #:color "blue") A keyword is associated with a formal or actual argument by (rectangle #:color "blue" 10 20) placing the keyword before the argument name or expression. For (rectangle #:color "blue" 10) example, a rectangle procedure that accepts two by-position (rectangle 10 #:color "blue" 20) arguments and one argument with the #:color keyword can be Our goals in a design for keyword and optional arguments written as include providing especially clear error messages and enforcing a consistent syntax for keyword arguments. Toward these goals, two 1 See Section 7.7 for a discussion on this choice of keyword syntax. aspects of our design set it apart from previous approaches in Lisp and Scheme: • Keywords are distinct from symbols, and they are not self- quoting as expressions. Permission to make digital or hard copies of all or part of this work for personal or classroom use is granted without fee provided that copies are not made or distributed For example, the form for profit or commercial advantage and that copies bear this notice and the full citation #:color on the first page. To copy otherwise, to republish, to post on servers or to redistribute to lists, requires prior specific permission and/or a fee. in an expression position is a syntax error, while 2009 Workshop on Scheme and Functional Programming (rectangle #:color "blue") 1 is a call to rectangle with the #:color argument "blue". (lambda hkw-formalsi hbodyi ...+) In the latter case, the procedure-application form treats the #:color keyword as an argument tag, and not as an expres- hkw-formalsi = (hformal-argi ...) sion. Every keyword in an application must be followed by a | (hformal-argi ...+ . hrest-idi) value expression, so the form | hrest-idi (rectangle #:color #:filled? #f) hformal-argi = hidi is rejected as a syntax error, because #:color lacks an ar- | [hidi hdefault-expri] gument expression; if keywords could be expressions, the call | hkeywordi hidi would be ambiguous, because #:filled? might be intended | hkeywordi [hidi hdefault-expri] as the #:color argument to rectangle. ... means “zero or more,” ...+ means “one or more,” hidi or hrest-idi • Keywords are not passed as normal arguments to arbitrary pro- matches an identifier, hexpri or hdefault-expri matches an expression, cedures, where they might be confused with regular procedure hkeywordi matches a keyword, and hbodyi matches a definition or arguments. Instead, a different calling convention is used for expression in an internal-definition context keyword arguments. For example, Figure 1: Extended grammar for lambda (cons #:color "blue") does not create a pair whose first element is a keyword and (hproc-expri hactual-argi ...+) second element is a string. Evaluating this expression instead hactual-argi = hexpri reports a run-time error that cons does not expect keyword | hkeywordi hexpri arguments. Although a keyword is not self-quoting as an expression, a Figure 2: Extended grammar for procedure application keyword is a first-class value in PLT Scheme. A keyword can be quoted to produce a valid expression, as in ’#:color and (cons ’#:color "blue"), where the latter creates a pair whose first > (define polygon element is a keyword. Keyword values and quoted-keyword expres- (lambda (n [side-len (/ 12 n)] . options) sions are useful for creating a procedure that accepts arbitrary key- (list n side-len options))) word arguments and processes them explicitly. Keyword values are > (polygon) also useful in reflective operations that inspect the keyword require- procedure polygon: no clause matching 0 arguments ments of a procedure. By convention, PLT Scheme programmers > (polygon 3) do not use keywords for run-time enumerations and flags, leaving (3 4 ()) those roles to symbols and reserving keywords for syntactic roles. > (polygon 3 7) (3 7 ()) The rest of the paper proceeds as follows. Section 2 describes > (polygon 3 7 ’solid ’smooth) the syntax and semantics of keyword and optional arguments in (3 7 (solid smooth)) PLT Scheme. Section 4 describes our implementation of keyword arguments. Section 5 provides some information on the perfor- When the hkeywordi hidi or hkeywordi [hidi hdefault-expri] mance of keyword and optional arguments. Section 6 reports on forms of hformal-argi are used to construct a lambda expres- our experience using keywords in PLT Scheme. Section 7 describes sion, the resulting procedure accepts keyword-tagged arguments previous designs for keywords in Lisp and Scheme and relates them in addition to the arguments that would be accepted without the to our design. keyword-tagged arguments. Arguments using the hkeywordi hidi form are required, while arguments using the hkeywordi [hidi hdefault-expri] form are optional. As with the keywordless [hidi 2. Syntax and Semantics hdefault-expri] form, each keyword-tagged hdefault-expri is eval- Figure 1 shows the full syntax of PLT Scheme’s lambda. In a uated for a given application of the procedure if no actual argument hkw-formalsi, all hidis must be distinct, including hrest-idi, and is tagged with the corresponding hkeywordi, and the preceding ar- all hkeywordis must be distinct. A required non-keyword argument gument hidis are in the environment of each hdefault-expri. When (i.e., the first case of hformal-argi) must not follow an optional non- hdefault-expris are evaluated for multiple arguments, they are eval- keyword argument (i.e., the second case of hformal-argi). uated in the order declared in the lambda expression, independent A lambda form that is constructed using only the hidi form of of whether the arguments have a keyword tag or the order of key- hfomal-argi has the same meaning as in standard Scheme (Sperber word tags on actual arguments. Actual arguments that are tagged 2007). A lambda form that uses only the hidi and [hidi hdefault- with a keyword can be supplied in any order with respect to each expri] forms of hformal-argi can be converted to an equivalent other and with respect to by-position arguments. case-lambda form; the appendix shows the conversion pre- > (define polygon cisely in terms of syntax-rules. For each optional argument (lambda (n [side-len (/ 12 n)] that is not supplied in an application of the procedure,