Procedure Arity Inspection
David Van Horn
This SRFI is currently in withdrawn status. Here is an explanation of each status that a SRFI can hold. To provide input on this SRFI, please send email to srfi-102@nospamsrfi.schemers.org
. To subscribe to the list, follow these instructions. You can access previous messages via the mailing list archive.
Many Scheme systems provide mechanisms for inspecting the arity of a procedural value, making it a common feature, however there is no standard interface. As a result there is no portable way to observe the arity of a procedure without actually applying it. This SRFI proposes a simple interface that is consistent with existing Scheme systems' facilities and prior proposals.
This proposal identifies a common, core set of operations that make it possible to inspect the arity of procedures and determine if a given procedure accepts a given number of arguments. These operations are already supported in several Scheme systems and it should be easy to add support in many more systems.
In preparing this proposal, the facilities available in Chez [1], Gauche [2], IronScheme [3], Larceny [4], MIT/GNU Scheme [5], PLT Scheme [6], and s7 [7] were reviewed. Also relevant is William D Clinger's 1996 straw proposal sent to the RnRS Authors mailing list [8]. Although there is some overlap among these systems, there are also many differences, precluding portability of code that relies on arity inspection. The most overlap occurs between Gauche, PLT Scheme, Larceny, and Clinger's proposal, and this forms the basis of this proposal. In particular, PLT Scheme and Gauche already implement this SRFI. Larceny implements a subset of this SRFI that makes it easy to portably define the remaining components and any Scheme that implements Clinger's proposal can likewise be easily and portably extended to implement this SRFI (such an extension is provided in the reference implementation section). The remaining systems provide interfaces in which this proposal is easily implemented.
A procedure to determine the arity of an arbitrary procedure's value
was discussed briefly, without result, at the June 1992 RnRS Authors
meeting [9].
In October 1995, version 0.29 of MzScheme added the arity
procedure for inspecting the arity of a procedure
[10]. That interface, which is the first this
SRFI author was able to locate that includes support for Dybvig and
Hieb's case-lambda
form [11], is
still supported in the current version of PLT Scheme
(renamed procedure-arity
) and has also been adopted by
Gauche.
In May 1996, William D Clinger submitted a straw proposal to the RnRS
Authors mailing list [8]. Shortly afterward
[12], Shriram Krishnamurthi suggested the
proposal take into account the possibility of extending Scheme
with case-lambda
(which came to pass with the
finalization of SRFI 16 [13] and again with the
ratification of R6RS Standard Libraries [14]),
in which a procedure has multiple traditional arities.
Clinger's 1996 proposal for inspecting arities largely overlaps with
this SRFI. The major differences are that Clinger's proposal:
case-lambda
syntax of Dybvig and Hieb, SRFI 16, and R6RS; and
Following Clinger's proposal, Scheme systems need not provide complete information for the arity of all procedures. There will be implementations for which this kind of information can always be provided, but there will also be systems or modes of operation in which this kind of information is not appropriate. Thus this SRFI specifies an interface only, and makes very few guarantees about what an implementation must produce when used. Scheme implementations are encouraged to document the guarantees supported in their particular implementation beyond those described here, if any. Portable programs should not depend on the behaviour of this feature beyond what is specified in this document.
Many Scheme systems provide procedure inspection facilities beyond arity inspection. For example, many Schemes provide mechanisms for recovering source code, source location, and documentation. This SRFI focuses solely on the ability to retrieve arity information from procedural values; features for retrieving other kinds of information from procedures are considered beyond the scope of this proposal and left for future SRFIs to take up.
Many Scheme systems provide a library of operations for procedural values. For example, many Schemes provide library procedures for composing, currying, and iterating procedures. A general library for procedures is considered beyond the scope of this proposal and left for future SRFIs.
At least one Scheme system, PLT Scheme, provides operations for restricting the set of acceptable arities for a procedure. These operations do not seem to be in wide use (outside of PLT) and are therefore not considered in this proposal.
Inspecting procedure arity is not without its caveats and there are good reasons for not supporting such a feature. This section outlines some of those reason. The following analysis was developed during a conversation with R. Kent Dybvig and has been lightly edited.
An arity-reporting procedure may be misleading because it appears to
but does not actually guarantee that an arity error will not occur
when a procedure is called with an arity it is reported to accept (in
fact, all that is guaranteed is that if a procedure is applied to
arguments it is reported not to accept, an arity error is
guaranteed to occur). It is common for a procedure to be a wrapper
for one or more other procedures (for tracing, dispatch, or other
reasons), to take an arbitrary number of arguments, and to apply one
of the wrapped procedures to those arguments. This occurs, for
example, when using the reference implementation
of case-lambda
given in SRFI 16 or the implementation
given in R6RS. The effective number of arguments is that of the
wrapped procedure that is actually called, but an arity-reporting
procedure would report the number of arguments of the wrapping
procedure.
Before using a procedure, it is necessary to know how many arguments it takes, their types, the ranges of acceptable values, and of course what it will and will not do. An arity-reporting procedure seems like a drop in the bucket and may not even be as useful as it seems at first blush.
A more subtle issue is that the mere existence of an arity-reporting procedure and the like might discourage people from using wrappers such as described, insidiously reducing a language's expressiveness even as they seem to increase it.
An arity object represents the arity of a procedure. An
arity object is either #f
, an exact non-negative integer,
an arity-at-least object, or a list of exact non-negative integers and
arity-at-least objects.
An arity-at-least object represents the arity (or one of the
arities) of a procedure that accepts some number or more arguments.
This proposal does not specify the representation of arity-at-least
objects, other than to say that it must be disjoint from exact,
non-negative integers; lists; and #f
; and it must satisfy
the requirements below.
procedure: (procedure-arity proc) → arity
Produces an arity object representing the arity of proc. If
this procedure produces #f
, no information is available
for proc.
If this procedure produces an exact non-negative integer, k, then proc accepts exactly k arguments; applying proc to some number of arguments other than k will result in an arity error.
If this procedure produces an arity-at-least object, a,
then proc
accepts (arity-at-least-value a)
or more
arguments; applying proc to some number of arguments less
than (arity-at-least-value a)
will result in an
arity error.
If this procedure produces a list, then proc accepts any of the arities described by the elements of the list; applying proc to some number of arguments not described by an element of the list will result in an arity error.
procedure: (arity-at-least? obj) → bool
Returns #t
if obj is an arity-at-least object
and false otherwise.
procedure: (arity-at-least-value arity-at-least) →
k
Returns the exact non-negative integer denoting the minimum number of arguments required by the given arity-at-least object.
procedure: (procedure-arity-includes? proc k)
→ bool
Returns #t
if the proc can accept k
arguments and #f
otherwise. If this procedure
returns #f
, applying proc to k
arguments will result in an arity error.
A portable reference implementation of this SRFI that provides useful information is not possible. In its place we offer a portable implementation that does not provide useful information and implementation-specific implementations that do for PLT Scheme (a trivial wrapper for its native implementation of this interface) and Larceny (a trivial extension for its native implementation, which is sufficient for any Scheme that implements Clinger's 1996 proposal). Like PLT Scheme, Gauche natively supports this SRFI.
#!r6rs ;; A portable, non-informative implementation of SRFI 102. (library (srfi :102 procedure-arity) (export procedure-arity arity-at-least? arity-at-least-value procedure-arity-includes?) (import (rnrs base)) (define (procedure-arity proc) (assert (procedure? proc)) #f) (define (arity-at-least? obj) #f) (define (arity-at-least-value arity-at-least) (assert (arity-at-least? arity-at-least)) #f) (define (procedure-arity-includes? proc k) (assert (procedure? proc)) (assert (and (integer? k) (exact? k) (not (negative? k)))) #f))
#!r6rs ;; PLT Scheme specific implementation of SRFI 102. (library (srfi :102 procedure-arity) (export procedure-arity arity-at-least? arity-at-least-value procedure-arity-includes?) (import (only (scheme base) require only-in)) (require (only-in scheme/base procedure-arity arity-at-least? arity-at-least-value procedure-arity-includes?)))
#!r6rs ;; Larceny specific implementation of SRFI 102. ;; This implementation should be sufficient to extend any ;; implementation of Clinger's 1996 arity proposal to implement SRFI 102. (library (srfi :102 procedure-arity) (export procedure-arity arity-at-least? arity-at-least-value procedure-arity-includes?) (import (rnrs base) (primitives procedure-arity)) (define (arity-at-least? obj) (and (integer? obj) (inexact? obj) (not (negative? obj)))) (define (arity-at-least-value arity-at-least) (assert (arity-at-least? arity-at-least)) (inexact->exact arity-at-least)) (define (procedure-arity-includes proc k) (assert (procedure? proc)) (assert (and (integer? k) (exact? k) (not (negative? k)))) (let ((a (procedure-arity proc))) (and a (if (exact? a) (= k a) (< k a))))))
I would like to thank Eli Barzilay, R. Kent Dybvig, Matthias Felleisen, Daniel P. Friedman, and Shriram Krishnamurthi for answering questions on the history of arity inspection in Scheme. In particular, I would like to further thank R. Kent Dybvig for providing the analysis of why not to support arity inspection. I would like to thank Aaron W. Hsu for providing information on Chez Scheme's procedure inspection facilities. I am grateful to Michael Sperber for serving as SRFI editor. Support was provided by the National Science Foundation under Grant #0937060 to the Computing Research Association for the CIFellow Project.
Copyright (C) David Van Horn 2009. All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.