Scheme中`values`的工作原理是什么?结合R5RS定义解析误区
Scheme中
values的工作原理 嘿,这个误区真的很常见!我来帮你理清楚values到底怎么工作,还有你之前的理解错在哪。
首先先看你贴的R5RS标准里的values定义:
(define (values . things) (call-with-current-continuation (lambda (cont) (apply cont things))))
咱们一步步拆解这个代码的逻辑:
values是个能接任意多参数的函数,所有传进来的参数会被打包成列表things。- 它调用了
call-with-current-continuation(常简称call/cc),这个函数的作用是“捕获当前的执行上下文”——也就是所谓的“续延(continuation)”,简单说就是“当前表达式接下来要做的事”。 - 最关键的一步:
(apply cont things)是把things里的所有元素逐个作为独立参数传给续延,而不是把整个列表当一个参数传。
那你之前的误区出在哪?为什么(+ (values 1 2))不等于(apply + '(1 2))?
你得先搞清楚这个表达式里的续延是什么。当你写(+ (values 1 2))时,values的续延其实是“把返回的结果放到+的参数位置,然后执行加法运算”——但注意,这个续延只期待一个参数,因为语法上+这里只有一个参数位(你只写了(+ arg)的结构)。
所以当values尝试给续延传两个参数(1和2)时,续延接不住,自然就会报错,而不是像apply +那样把列表展开成多个参数给+。
那正确接收多值返回的方式是什么?得用专门处理多值的工具,比如call-with-values:
(call-with-values (lambda () (values 1 2)) +)
这个时候,call-with-values会先执行第一个lambda(它返回values 1 2的多值),然后把这多个值直接作为+的参数传进去,这就等价于(+ 1 2),结果就是3。
再换个方式理解续延:比如你写(let ((x (values 1 2))) x),这里values的续延是“把返回值赋值给x”,而x只能存一个值,所以同样会报错——续延只接受单个值,而values给了两个。
总结一下核心点:
values的作用是产生多个返回值,但这些值必须被支持多值的上下文接收,比如call-with-values、let-values这类特殊形式。- 普通的函数调用参数位是“逐个对应”的,续延只接受单个值,所以直接把
values放进去会触发错误,和apply的逻辑完全不一样。
内容的提问来源于stack exchange,提问作者Gradient
相关产品推荐
相关产品推荐

