我在尝试解决与宏变量范围相关的问题时发现了这个非常有用的SO页面。 why doesn't %let create a local macro variable?
总而言之,在宏中写%let x = [];
或%do x = [] %to [];
会:
这让我觉得非常不直观。我愿意打赌,由于这种设计选择,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宏变量范围的工作方式呢?
答案 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 Scoping在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