作用域对中缀sub的EVAL有何影响?为何两个sub处理逻辑不同?
作用域对Raku中缀sub与EVAL执行的影响分析
问题现象
首先,以下代码在全局作用域下执行完全符合预期:
sub infix:<mean>(*@a) { @a.sum / @a.elems } sub Mean (*@a) { @a.sum / @a.elems } say EVAL 'Mean 2, 6, 4'; # Output: 4 say EVAL '2 mean 6 mean 4'; # Output: 4
当调用普通sub的EVAL语句放在独立作用域中时,运行依然正常:
{say EVAL 'Mean 2, 6, 4';} # Output: 4
但将调用中缀sub的EVAL语句放在独立作用域中时,会触发编译错误:
{say EVAL '2 mean 6 mean 4';}
错误信息如下:
=抱歉!= 编译.../EVAL_1时出错
连续两个术语
在.../EVAL_1:1行
------> 2⏏ mean 6 mean 4
期待以下任意项:
infix
infix stopper
statement end
statement modifier
statement modifier loop
核心差异原因
1. 普通sub与中缀sub的本质区别
- 普通命名sub(如
Mean)属于包级符号,默认会注册到当前包的符号表中。无论在哪个嵌套作用域中执行EVAL,只要符号表中存在这个sub,EVAL就能通过符号查找机制找到并调用它。 - 中缀运算符
infix:<mean>属于语法扩展定义,它的生效依赖于编译阶段的语法环境。编译器需要在编译时识别到这个语法规则,才能将2 mean 6解析为中缀运算表达式。
2. EVAL的编译上下文限制
EVAL在执行时会分为编译和运行两个阶段:
- 对于普通sub的调用字符串,EVAL编译阶段只需识别
Mean是一个调用符号,运行时直接从包符号表中获取对应的sub即可。 - 对于中缀运算的字符串,EVAL的编译阶段是在当前独立作用域内进行的,而外部作用域定义的中缀语法规则不会自动渗透到这个嵌套的编译上下文里。此时编译器无法识别
mean作为中缀运算符的身份,会把2和mean当成两个连续的语法术语,从而抛出"连续两个术语"的编译错误。
解决方法(可选)
如果需要在独立作用域的EVAL中使用外部定义的中缀运算符,可以通过显式导入的方式让编译上下文识别该语法:
{ our infix:<mean>; # 声明当前作用域可访问该中缀符号 say EVAL '2 mean 6 mean 4'; # 正常输出4 }
或者直接在EVAL字符串中导入:
{say EVAL 'use OUR infix:<mean>; 2 mean 6 mean 4';} # 正常输出4
内容的提问来源于stack exchange,提问作者Jim Bollinger
相关产品推荐
相关产品推荐

