2016-02-21 15 views
5

Ho trovato questa pagina SO molto utile durante il tentativo di risolvere un problema correlato all'ambito della variabile macro. why doesn't %let create a local macro variable?Perché non sono le variabili macro SAS Ambito locale per impostazione predefinita?

Quindi, per riassumere, la scrittura %let x = []; o %do x = [] %to []; in una macro:

  • creare un locale ambito macro variabile x se non c'è un "x" già nella tabella dei simboli globale, o
  • aggiorna la variabile macro globale "x" se una "x" è nella tabella dei simboli globale

Questo mi sembra molto non intuitivo. Sarei disposto a scommettere che ci sono un sacco di bug nella zona selvaggia SAS a causa di questa scelta progettuale. Raramente vedo% istruzioni locali in macro, anche sopra istruzioni di loop usando nomi di variabili comuni come "i" o "counter". Per esempio, ho appena tirato sulla prima carta con la parola "macro" nel titolo da questo elenco di Sugi e SAS Forum Globale carte http://www.lexjansen.com/cgi-bin/xsl_transform.php?x=sgf2015&c=sugi

E in effetti, ho trovato questo codice nel primo documento convegno SAS ho aperto :

%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

Guai a chi chiama% bandiera e ha anche la propria variabile & j. Potrebbero facilmente finire senza errori di log ma risultati fasulli perché il loro & j è 4 ovunque dopo aver chiamato% flag, che sarà (dall'esperienza) un bug che non è divertente rintracciare. O peggio, potrebbero non riconoscere mai che i loro risultati sono falsi.

Quindi la mia domanda è: perché è stata presa la decisione di non avere tutte le variabili macro come scope locali di default? Ci sono dei buoni motivi per cui l'ambito delle variabili macro SAS funziona come fa?

+1

Questa è una domanda interessante ma potrebbe essere off/topic per s.o. poiché ora può esserci una risposta giusta, è vicina all'opinione. Suggerire di chiedere a communities.sas.com o SAS-L, entrambi hanno più discussioni. Detto questo, sono d'accordo con te sul fatto che le regole di scoping non sono intuitive e hanno un'alta probabilità di causare bug in natura. – Quentin

+0

Grazie per il suggerimento Quentin. Sulla base della descrizione del tag "language-design" e dei tipi di domande che vedo qui per quel tag, non pensavo che questa domanda sarebbe fuori tema su SO. Forse lo posterò su uno dei siti che hai citato anche tu. –

+0

Un buon punto per quanto riguarda il tag di design della lingua, avrei pensato che molte di quelle domande fossero off-topic. (Anche quando pensavo che fosse OT, stavo ancora scrivendo una risposta.) – Quentin

risposta

4

In gran parte, poiché SAS è una lingua di 50 anni che esisteva prima dello lexical scoping era chiaramente preferito.

SAS dispone di una combinazione dei due concetti di ambito, ma è prevalentemente dinamico nell'ambito di un ambito a meno che non venga modificato intenzionalmente. Ciò significa che solo leggendo la definizione di una funzione, non è possibile stabilire quali variabili saranno disponibili in fase di esecuzione; e le dichiarazioni di assegnazione si applicano alla versione di una variabile che è attualmente disponibile in fase di esecuzione (piuttosto che essere applicata per essere nello scope più locale disponibile).

Ciò significa che il compilatore di macro non è in grado di stabilire se una determinata istruzione di assegnazione intende assegnare una variabile macro locale o una variabile macro dell'ambito di validità possibilmente esistente al momento dell'esecuzione. SAS potrebbe applicare la variabile macro locale come si afferma, ma ciò trasformerebbe SAS in un linguaggio di scope lessicale, che non è desiderato sia in base alla coerenza con il passato (mantenendo la compatibilità con le versioni precedenti) sia in base alla funzionalità; SAS offre la possibilità di applicare l'ambito lessicale (utilizzare %local) ma non offre la possibilità di modificare intenzionalmente una variabile in un ambito più elevato (una qualche forma di parent?) Diversa da %global.

Si noti che Dynamic Scoping era molto comune negli anni '60 e '70. S-Plus, Lisp, ecc. Avevano tutti scope dinamici. SAS tende a preferire la retrocompatibilità il più indietro possibile. SAS è anche analisti di uso comune, piuttosto che programmatori, e quindi deve evitare la complessità ogni volta che è possibile. Offrono %local per quelli di noi che vogliono i vantaggi del scoping lessicale

+0

Grazie per l'intuizione Joe. Posso chiederti di chiarire che cosa intendi che SAS "non offre la possibilità di alterare intenzionalmente una variabile in un ambito superiore ... diverso da% globale?"Nel codice nella mia domanda, se ci fosse un'istruzione"% let j = 5 "sopra la definizione della macro, la macro flag% cambierebbe il valore di quell'ambito superiore e j senza un'istruzione globale di%. Presumibilmente a volte è intenzionale. –

+1

La funzione 'CALL SYMPUTX()' consente di sovrascrivere il comportamento predefinito della scrittura sulla variabile macro localmente definita, ma solo scrivendo sull'ambito macro 'GLOBAL' Non è possibile utilizzarlo per scrivere su un livello di ambito intermedio arbitrario – Tom

+2

@Max, è esattamente perché SAS ha un ambito dinamico, ma non è qualcosa che puoi 'attivare' quando lo vuoi.È possibile forzare una variabile ad essere localmente scope (efficacemente lessicalmente con scope) ma non si può forzare una variabile per essere meno localmente ambito ma non globale - quindi non puoi forzarlo ad essere in un ambito intermedio. – Joe

4

Rispondere PERCHÉ sono state definite le regole di scoping in questo modo è difficile per me, senza conoscere la cronologia del linguaggio macro.

Quando ho imparato il linguaggio macro (in 6.12), ho avuto la fortuna di essere istruito fin da subito che le macro dovevano sempre dichiarare le loro variabili come% LOCAL, a meno che non avessero una buona ragione per non farlo. A volte, se una macro var non è stata dichiarata come% local o% global, inserirei anche un commento /* Not Local: MyMacVar */ per documentare che non intendevo dichiarare l'ambito (questo è inusuale ma a volte utile). Mi addolora vedere documenti UG, risposte SO, ecc. Che non dichiarano variabili come% LOCAL.

Ho intenzione di indovinare (questa è solo una supposizione), che c'era una versione precedente di SAS che aveva variabili macro (globali) per la generazione di testo nel codice, ma non aveva macro. Quindi, in una tale versione, le persone si sarebbero abituate ad avere molte variabili macro globali e i problemi associati (ad esempio, collisioni). Quindi, quando SAS ha progettato macro, la domanda sarebbe venuta fuori, "Posso fare riferimento alle mie macro vars all'interno di una macro?" E il designer ha scelto di rispondere "sì, non solo puoi fare riferimento a loro, puoi anche assegnare loro dei valori, e lo renderò più semplice consentendoti di farlo in modo predefinito, ma anche una macro creerà il proprio ambito che può contenere variabili macro locali Se si fa riferimento a una macro var o si assegna una macro var che ha lo stesso nome di una macro var esistente in un ambito globale (o qualsiasi ambito esterno), suppongo che si stia facendo riferimento alla macro globale variabile (come sei già abituato), a meno che tu non abbia dichiarato esplicitamente la variabile var come% LOCAL."

Dal punto di vista dell'attuale macro/macro sviluppatore di macro, la maggior parte della gente pensa che la maggior parte delle macro vars globali dovrebbero essere evitate e uno dei vantaggi del linguaggio macro è che fornisce macro che consentono la modularizzazione/incapsulamento/informazione Quando si osservano da questo punto di vista, le variabili locali% sono più utili e le variabili macro che non sono dichiarate come% locali sono una minaccia per l'incapsulamento (cioè la minaccia di collisione). Quindi tenderei ad essere d'accordo sul fatto che se ridisegnassi il linguaggio macro, vorrei rendere le variabili macro% locali per impostazione predefinita.Ma ovviamente a questo punto, è troppo tardi per un cambiamento.

+0

[Questo account della cronologia SAS] (http://www.globalstatements.com/sas/differences) non è abbastanza dettagliato da confermare, ma sembra che il linguaggio macro sia arrivato a tappe che potrebbero aver portato a ciò tu descrivi. – John

0

Quindi non abbiamo potuto fare questo o almeno non senza una nuova dichiarazione dichiarativa

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 
Problemi correlati