Scheme中嵌套可变参数的解析规则及无参调用报错问题
解析Scheme中
(nested_var_arg . (arg_1 . args))的参数列表 首先明确结论:你写的这个过程定义,本质等价于直接使用(lambda (arg_1 . args) ...),它要求调用时至少传入1个参数,这就是无参调用报错的核心原因。
详细拆解语法逻辑
Scheme的(define (name . formals) body...)是语法糖,完全等价于(define name (lambda formals body...))。这里的关键是:你写的. (arg_1 . args)中,(arg_1 . args)是作为lambda的参数列表存在的,而非“嵌套可变参数”。
按照R7RS 4.1.4对lambda参数列表的规定:
- 当参数列表是
(arg_1 . args)这种点对形式时,arg_1是必填参数,调用时必须至少传入1个参数绑定给它;剩下的所有参数(可以是0个)会被打包成列表绑定给args。 - 对比普通可变参数
(define (var_arg . lst) ...):这里的formals是单个变量lst,等价于(lambda lst ...),这种形式允许接收任意数量参数(包括0个),所有参数会被打包成列表lst。
你可能误解了R7RS的示例:文档里的(x y . z)是lambda参数列表的直接写法,它要求至少2个参数,z接收剩余参数。Scheme本身不存在“嵌套可变参数”的概念,参数列表要么是单个变量(支持任意参数),要么是包含必填项和剩余项的列表/点对结构。
如何让过程支持0个参数
如果需要nested_var_arg能接收0个参数,你可以改用单个变量接收所有参数,再手动解构:
(define (nested_var_arg . all-args) (let ((arg_1 (if (null? all-args) #f (car all-args))) (args (if (null? all-args) '() (cdr all-args)))) (if (list? args) (begin (displayln "args") (displayln args)) (if arg_1 (displayln arg_1) (displayln "nothing")))))
此时调用(nested_var_arg)时,all-args为空列表,arg_1被设为#f,args为空列表,过程可以正常执行。
内容的提问来源于stack exchange,提问作者An5Drama
相关产品推荐
相关产品推荐

