为什么SAS默认情况下没有本地范围的SAS宏变量?

时间:2016-02-21 07:02:06

标签: scope sas language-design dynamic-scope

我在尝试解决与宏变量范围相关的问题时发现了这个非常有用的SO页面。 why doesn't %let create a local macro variable?

总而言之,在宏中写%let x = [];%do x = [] %to [];会:

  • 如果没有" x"则创建一个本地范围的宏变量x已经在全局符号表中,或
  • 更新全局范围的宏变量" x"如果" x"在全局符号表中

这让我觉得非常不直观。我愿意打赌,由于这种设计选择,SAS荒野中有大量的漏洞。我很少在宏中看到%local语句,甚至在使用常见变量名称的循环语句之上,例如" i"或"柜台。"例如,我只是用#34;宏"这个词拉出了第一篇论文。在SUGI和SAS全球论坛论文清单的标题中 http://www.lexjansen.com/cgi-bin/xsl_transform.php?x=sgf2015&c=sugi

事实上,我在我开的第一份SAS会议论文中找到了这段代码:

%macro flag;
data CLAIMS;
 set CLAIMS;
 %do j= 1 %to 3;
 if icd9px&j in (&codelist)
 then _prostate=1;
 %end;
run;
%mend;
%flag;

http://support.sas.com/resources/papers/proceedings15/1340-2015.pdf

任何打电话给%flag并且拥有自己的& j变量的人都有祸了。他们可以很容易地结束没有日志错误但是结果是假的,因为他们的& j在他们调用%flag之后到处都是4,这将是(从经验)一个跟踪没有乐趣的错误。或者更糟糕的是,他们可能永远不会认识到他们的结果是假的。

所以我的问题是,为什么决定不将所有宏变量默认为本地范围?有没有充分的理由说明SAS宏变量范围的工作方式呢?

3 个答案:

答案 0 :(得分:4)

回答为什么在不知道宏语言历史的情况下,以这种方式定义的范围规则对我来说很难。

当我学习宏语言(在6.12上)时,我很幸运能够从早期开始学习,宏应该总是将它们的变量声明为%LOCAL,除非他们有充分的理由不这样做。有时如果宏var未被声明为%local或%global,我甚至会在其中添加/* Not Local: MyMacVar */注释来记录我不打算声明范围(这是不寻常的,但有时很有用)。我很难看到UG论文,SO答案等没有将变量声明为%LOCAL。

我要猜测(这只是一个猜测),有一些早期版本的SAS有(全局)宏变量用于代码中的文本生成,但没有宏。因此,在这样的版本中,人们会习惯于拥有许多全局宏变量以及相关的问题(例如冲突)。然后,当SAS设计宏时,问题就出现了,“我可以从宏内引用我的宏变量吗?”设计师选择回答“是的,你不仅可以引用它们,还可以为它们赋值,而且我可以通过默认允许你这样做来实现它。但是,宏也会创建自己的范围可以保存本地宏变量。如果引用宏var或分配一个与全局范围(或​​任何外部范围)中存在的宏var同名的宏var,我将假设您引用了全局宏变量(就像你已经习惯的那样),除非你已经明确地将宏变量声明为%LOCAL。“

从目前的宏语言/宏观开发者的角度来看,大多数人认为应该避免大多数全球宏观变量。宏语言的一个好处是它提供了允许模块化/封装/信息隐藏的宏。从这个角度来看,%局部变量更有用,未声明为%local的宏变量是封装的威胁(即碰撞威胁)。所以我倾向于同意,如果我重新设计宏语言,我会默认将宏变量设为%local。但当然,在这一点上,改变已经太晚了。

答案 1 :(得分:4)

很大程度上,因为SAS是一种50岁的语言,它在lexical scoping之前就已经存在了。

SAS有两种范围概念的混合,但除非您有意更改它,否则主要是动态范围。这意味着只需通过读取函数的定义,就无法确定在运行时哪些变量可用;和赋值语句适用于当前在运行时可用的变量版本(而不是强制在最可用的本地范围内)。

这意味着宏编译器无法判断特定的赋值语句是否要分配本地宏变量,或者是否可能存在于运行时更高范围的宏变量。 SAS可以在您声明的情况下强制执行本地宏变量,但这会将SAS转变为词汇范围界定语言,基于与过去的一致性(保持向后兼容性)和基于功能,这是不可取的。 SAS提供了强制词法作用域的能力(使用%local),但不提供有意改变更高范围(某种形式的parent?)而不是%global的变量的能力。

请注意,Dynamic Sc​​oping在60年代和70年代非常普遍。 S-Plus,Lisp等都有动态范围。 SAS倾向于尽可能地追求向后兼容性。 SAS也是常用的分析师,而不是程序员,因此需要尽可能避免复杂性。他们为我们这些希望获得词汇范围优势的人提供%local

答案 2 :(得分:0)

然后我们无法做到这一点,或者至少没有新的声明性声明。

33         %let c=C is global;
34         %macro b(arg);
35            %let &arg=Set by B;
36            %mend b;
37         %macro a(arg);
38            %local c;
39            %b(c);
40            %put NOTE: &=c;
41            %mend a;
42         %a();
NOTE: C=Set by B