(+ (values 1) (values 2)) 没问题,结果应该是3。但是在values 表达式中不需要的值不会被自动忽略。事实上,(+ 1 (values 2 3)) 的行为在 R6RS 和 R7RS 方案中都是未指定的。
来自values 的条目来自R6RS 11.15 [强调我的]:
将它的所有参数传递给它的延续......
一个序列中所有非最终表达式的延续
表达式,例如lambda、begin、let、let*、letrec、
letrec*、let-values、let*-values、case 和 cond 表格,
通常取任意数量的值。
除了这些和call-with-values 创建的延续,
let-values 和 let*-values,延续隐式接受
单个值,例如 的延续和
过程调用的 或中的 表达式
条件,只取一个值。通过的效果
未定义此类延续的不适当数量的值。
R7RS 在 6.10 中有类似的语言:
未指定向未以其中一种方式创建的延续传递任何值或多个值的效果。
(+ (values 1) (values 2)) 可以的原因是过程调用中操作数的延续只取一个值。 (values 1) 和 (values 2) 各自为各自的延续提供了一个值。
call-with-values 用于将多个值的生产者与使用这些值的过程连接起来。 call-with-values 的第一个参数应该是一个不带参数并产生要使用的值的过程。第二个参数应该是一个过程,它接受第一个过程产生的值的数量:
> (call-with-values (lambda () (values 2 3))
(lambda (x y) (+ 1 x y)))
6
请注意,上述call-with-values 的使用要求消费者接受生产者产生的值的数量,因为当过程不接受传递给它的参数数量时,Scheme 要求实现引发错误:
> (call-with-values (lambda () (values 2 3 4))
(lambda (x y) (+ 1 x y)))
Exception: incorrect argument count in call (call-with-values (lambda () (values 2 3 4)) (lambda (x y) (+ 1 x y)))
如果希望忽略额外的参数,则必须针对该目标设计消费者。在这里,消费者被设计为忽略除第一个参数之外的所有参数:
> (call-with-values (lambda () (values 2 3 4))
(lambda (x . xs) (+ 1 x)))
3