Jsonnet函数引用透明性存疑:替换函数定义为何结果不同?
为什么替换Jsonnet函数定义后语义不一致?
Jsonnet语言参考手册指出:
Jsonnet中的函数具有引用透明性,即任何函数调用都可替换为其定义,且不改变程序语义。
但以下两个Jsonnet程序的输出却存在差异:
程序1:使用函数调用
{ c: local a = function() self.b; {x: a(), b: 'inner'}, b: 'outer' }
输出:
{ "b": "outer", "c": { "b": "inner", "x": "outer" } }
程序2:直接替换函数定义
{ c: {x: self.b, b: 'inner'}, b: 'outer' }
输出:
{ "b": "outer", "c": { "b": "inner", "x": "inner" } }
二者x键对应的值一个是outer,一个是inner,这是为什么?
原因解释
差异的核心在于**self的绑定时机与函数的作用域规则**:
- 在程序1中,函数
a是在顶层对象的作用域下定义的(local a = function() self.b),这里的self在函数定义时就绑定了顶层对象(也就是包含b: 'outer'的那个外层对象)。当在子对象里调用a()时,函数内部的self依然指向顶层对象,因此取到的是'outer'。 - 在程序2中,
self.b直接写在c的子对象内部,此时self绑定的是当前的子对象({x: self.b, b: 'inner'}),因为代码是在这个子对象的上下文中求值的,所以取到的是子对象自身的b值'inner'。
你觉得是直接替换函数体,但实际上函数的引用透明性要求替换时保留函数的作用域绑定——正确的替换方式不是把函数体代码直接挪到调用位置,而是要维持self原本绑定的作用域。错误的替换改变了self的上下文,才导致语义变化,并非Jsonnet的引用透明性失效。
内容的提问来源于stack exchange,提问作者Evan Aad
相关产品推荐
相关产品推荐

