2016-02-21 19 views
5

マクロ変数のスコープに関連する問題を解決しようとしているときに、この非常に役立つSOページが見つかりました。 why doesn't %let create a local macro variable?SASマクロ変数がローカルスコープでないのはなぜですか?

だから、マクロ意志で%let x = [];または%do x = [] %to [];を書いて、要約する:なし「x」はグローバルシンボルテーブルに既に存在しない場合、ローカル・スコープマクロ変数xを作成

  • 、または
  • "x"がグローバルシンボルテーブルにある場合は、グローバルスコープマクロ変数 "x"を更新してください。

これは非常に非直感的です。 SASの荒野にはこのデザインの選択肢のためにたくさんのバグがあることを喜んで賭けています。 "i"や "counter"のような一般的な変数名を使ったループ文の上でさえ、マクロ内の%local文をめったに見ることはほとんどありません。たとえば、SUGIとSAS Global Forumの論文リストのタイトルに「マクロ」と書かれた最初の論文を取り上げたばかりです 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

%フラグを呼び出し、また、独自の& j変数を持っている人がたに災い。彼らは容易にログエラーではなく、彼らの& jがどこからでも%flagを呼び出した後であるため、偽の結果に終わることがあります。あるいは悪いことに、彼らは結果が偽であることを決して認識しないかもしれません。

私の質問は、マクロ変数をすべてデフォルトでローカルスコープにしないようにしたのはなぜですか? SASマクロ変数の有効範囲がそのように機能する理由はありますか?

+1

これは興味深い質問ですが、s.oのトピックであるかもしれません。正解があるかもしれないので、意見に近いです。 communities.sas.comまたはSAS-Lに質問することを提案するには、より多くの議論が必要です。つまり、スコープルールは直感的ではなく、野生のバグを引き起こす可能性が高いことに私は同意します。 – Quentin

+0

クエンティンの提案に感謝します。 "language-design"タグの説明と、このタグについてここで参照している質問のタイプに基づいて、私はこの質問がSOの話題とはならないとは思わなかった。たぶん私はあなたが同様に言及したサイトの1つにこれを投稿します。 –

+0

言語デザインのタグに関する良い点は、これらの質問の多くが話題外であったと思い込んでいたと思います。 (私がそれがOTだと思ったとしても、私はまだ答えを書くつもりでした): – Quentin

答えて

4

大いにSASは、lexical scopingの前に存在した50歳の言語であることが明らかに好ましいと言えます。

SASには2つのスコープ概念が混在していますが、意図的に変更しない限りほとんどの場合動的スコープになります。つまり、関数の定義を読むだけでは、実行時にどの変数を利用できるかを知ることはできません。代入文は、実行時に現在利用可能な変数のバージョンに適用されます(利用可能な最もローカルスコープになるよう強制されるのではなく)。

これは、特定の代入文がローカルマクロ変数、または実行時に存在する可能性が高いスコープマクロ変数を割り当てることを意図しているかどうかをマクロコンパイラが判断できないことを意味します。 SASは、あなたが述べているようにローカルマクロ変数を強制することができますが、SASは語彙スコープ言語になります。これは、過去との一貫性(下位互換性を維持する)と機能性に基づいて望ましくありません。 SASは語彙スコープを適用する機能を提供しています(%localを使用)が、%global以外の高いスコープ(何らかの形式のparent?)を意図的に変更する機能はありません。

ダイナミックスコープは、60年代と70年代の非常に一般的なものでした。 S-Plus、Lispなどはすべて動的スコープを持っていました。 SASは、後方互換性を可能な限り後ろ向きにする傾向があります。 SASはプログラマではなく一般的に使用されるアナリストでもあり、可能な限り複雑さを避ける必要があります。彼らは%localを提供しています。私たちは語彙的スコープの利点を望んでいます。

+0

洞察ジョーをありがとう。 SASが、 "%global"以外のより高いスコープで変数を意図的に変更する機能を提供していないということを明確にするよう依頼できますか?"私の質問のコードでは、マクロ定義の上に"%let j = 5 "ステートメントがあれば、%flagマクロは%globalステートメントなしで上位スコープ&jの値を変更します。 –

+1

'CALL SYMPUTX()'関数を使うと、最もローカルに定義されたマクロ変数に書き込むデフォルト動作をオーバーライドすることができますが、 'GLOBAL'マクロスコープに書き込むだけです。 。 – Tom

+2

@Max、それはSASが動的にスコープされているからです - しかし、それはあなたが望むときにオンにできるものではありません。変数を強制的にローカルスコープ(効果的にレキシカルスコープ)にすることはできますが、ローカルスコープは狭くてグローバルではないため、中間スコープにすることはできません。 – Joe

4

このように定義されたスコープルールは、マクロ言語の履歴を知らなくても、私にとっては難しいのですか?

私がマクロ言語(6.12)を学んだとき、私は本当に良い理由がない限り、その変数が%LOCALであることをマクロが常に宣言しなければならないということを、早くから教えてくれたことは幸運でした。マクロvarが%localまたは%globalと宣言されていない場合、スコープを宣言するつもりはないことを文書化するために、/* Not Local: MyMacVar */のコメントを追加することさえあります(これは珍しいが時に便利です)。変数を%LOCALとして宣言していないUGの論文、SOの回答などを見るのは苦労します。

私は推測するつもりです(これは単なる推測です)、コードのテキスト生成用に(グローバル)マクロ変数を持つSASの初期バージョンがいくつかありましたが、マクロはありませんでした。そのようなバージョンでは、人々は大量のグローバルマクロ変数や関連する問題(衝突など)に慣れていたでしょう。それから、SASがマクロを設計したときに、「マクロ内のマクロバーを参照できますか?」という質問が出てきました。そして、デザイナーは「はい、あなたがそれらを参照できるだけでなく、値をそれらに割り当てることができるだけでなく、あなたがデフォルトでそれを可能にすることによってそれを容易にするでしょう」と答えました。ローカルマクロ変数を保持できるマクロvarを参照するか、グローバルスコープ(または外部スコープ)内に存在するマクロvarと同じ名前のマクロvarを割り当てる場合は、グローバルマクロを参照していると仮定しますあなたが明示的にマクロvarを%LOCALと宣言していない限り、あなたはすでに慣れています)。"

現在のマクロ言語/マクロ開発者の視点から、大部分の人はほとんどのグローバルマクロバールを避けるべきだと考えています。また、マクロ言語のメリットの1つは、モジュール化/カプセル化/情報-hiding。この観点から見た場合、%local変数はより有用であり、%localと宣言されていないマクロ変数はカプセル化の脅威(衝突脅威)です。マクロ言語のマクロ変数はデフォルトでは%ローカルにしていますが、現時点では変更が遅すぎます

+0

[SASの歴史のこのアカウント](http://www.globalstatements.com/sas/differences)は、詳細を確認するのには十分詳細ではありませんが、マクロ言語が段階的になり、あなたは説明します。 – John

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 
関連する問題