racketarity

Using variable-arity function on values-expression


I ran into this toy example recently that has me a bit confused. Suppose I define a simple variable-arity function as below. Then, we are totally within our rights to run this both on one argument and on two.

(define (my-func . a) a)

(my-func 1)  ; evals to '(1)
(my-func 1 2)  ; evals to '(1 2)

The weird bit I've run into is if I try to pass it multiple arguments in one go using values as below:

(my-func (values 1 2))

I'd expect this to evaluate to the same thing as (my-func 1 2), but instead throws an arity-mismatch error, namely that it expected 1 argument but got 2.

Why is it expecting one argument if my-func is variable-arity? Does this have to do with the number of syntactic objects as arguments or is it something else?


Solution

  • In Racket, values construct multiple return values (often abbrev. as multiple values or values). Except the case where it's a single value, values cannot be passed as argument(s). Values can't be kept in a variable. Values are mostly useful when returned from a function, and when used in forms like define-values, etc. See this section of the Racket Reference for more details.

    To use the terminology from the above link, (my-func []) is a continuation that only accepts a single value. That's why in your program, it errors with the message "expects one, got two".

    What you are trying to do can be accomplished with call-with-values:

    (call-with-values (lambda () (values 1 2)) my-func)