Re: proposing a simpler mechanism R. Kent Dybvig 13 Nov 2009 16:22 UTC

> > What do you expect procedure-arity to return for a procedure which
> > accepts any number of arguments?  IEEE +inf?

> -1, presumably.  The numerical value isn't significant; its
> representation as a bit string in two's-complement is what matters,
> and for -1 that is a bit string of all ones.

Right.  In effect, a two's complement number has an infinite number of
sign bits.  For negative numbers, the sign bits are all one (set), which
allows procedure-arity to represent the arity of a procedure that accepts
n or more arguments, for any n.

Here are some examples:

bitmask   two's complement    proc accepts:

0         #b0...00000         nothing, i.e., it raises raises an exception
                              no matter how many arguments it receives
1         #b0...00001         zero arguments
2         #b0...00010         one argument
4         #b0...00100         two arguments
6         #b0...00110         one or two arguments
5         #b0...00101         zero or two arguments

-1        #b1...11111         any number of arguments
-2        #b1...11110         one or more arguments
-4        #b1...11100         two or more arguments
-3        #b1...11101         zero or two or more arguments
                              (but not one argument)

Here's a procedure an implementation might use to compute a bitmask for a
single formal parameter list represented in the obvious way.

(define formals->bitmask
  (lambda (fmls)
    (let loop ([fmls fmls] [n 0])
        [(null? fmls) (bitwise-arithmetic-shift-left 1 n)]
        [(symbol? fmls) (bitwise-arithmetic-shift-left -1 n)]
        [else (loop (cdr fmls) (+ n 1))]))))

(formals->bitmask '()) ;=> 1
(formals->bitmask '(a b)) ;=> 4
(formals->bitmask 'r) ;=> -1
(formals->bitmask '(a b . r)) ;=> -4

Here's another procedure that computes an aggregate bitmask for a list of
formal parameter lists, as for a case-lambda expression.

(define formals*->bitmask
  (lambda (fmls*)
    (apply bitwise-ior (map formals->bitmask fmls*))))

(formals*->bitmask '()) ;=> 0
(formals*->bitmask '((a) (a b))) ;=> 6
(formals*->bitmask '(() (a b . r))) ;=> -3

And for your bitmask-visualization pleasure:

(define print-bitmask
  (lambda (bitmask)
    (let f ([bitmask bitmask] [minbits 4])
        [(= bitmask 0)
         (display "#b0...0")
         (display (make-string minbits #\0))]
        [(= bitmask -1)
         (display "#b1...1")
         (display (make-string minbits #\1))]
         (f (bitwise-arithmetic-shift-right bitmask 1)
            (max (- minbits 1) 0))
         (write-char (if (bitwise-bit-set? bitmask 0) #\1 #\0))]))))

(print-bitmask 3)
> (print-bitmask -3)