Scheme中freeVariables函数set-elts契约违规问题排查与修复咨询
Scheme自由变量提取函数报错排查与修复
报错含义解释
set-elts: contract violation. expected: set? , given: x 这个错误的意思是:调用set-difference时传入的参数不符合要求——该函数要求两个参数都是data/set库定义的集合类型,但你传入的第二个参数是单个符号x(不是集合),触发了参数类型合约违反。
问题根源分析
你的代码存在三个核心问题:
- 类型不匹配:
data/set库的set-difference要求参数是集合,但你返回的是列表,且λ表达式中的绑定变量是单个符号(不是集合),直接传入就会报错。 - 未处理重复变量:原代码用
append拼接函数应用的子表达式结果,会保留重复变量(比如示例中的g出现两次),但题目要求输出去重后的结果。 - 冗余判断:语法定义里没有空表达式的情况,
(null? exp)的判断多余。
修复方案
改用集合来全程处理自由变量,天然解决去重和类型匹配问题,最后再转换为列表输出:
- 变量节点返回包含该变量的单元素集合
- λ表达式中,将绑定变量转为单元素集合,再与体的自由变量集合做差集
- 函数应用节点,将各子表达式的自由变量集合做并集
- 最终将集合转为列表,符合示例的输出格式
修复后的完整代码
#lang scheme (require data/set) (define (freeVariables exp) (cond [(symbol? exp) (set exp)] ; 变量返回单元素集合 [(eq? (car exp) 'λ) (let ((var (cadr exp)) (body (caddr exp))) ; 绑定变量转成集合,和body的自由变量做差集 (set-difference (freeVariables body) (set var)))] [else ; 函数应用:合并所有子表达式的自由变量集合 (apply set-union (map freeVariables exp))])) ; 可选包装:返回列表格式(和示例输出一致) (define (freeVariables-as-list exp) (set->list (freeVariables exp)))
验证结果
调用(freeVariables-as-list '(λ f (λ x (f ((t g) g))))),会输出(t g),完全符合题目要求。
内容的提问来源于stack exchange,提问作者Peter Kavinski
相关产品推荐
相关产品推荐

