2010-04-28 8 views
7

Il codice seguente restituisce 14 come ci si aspetterebbe:scoping lessicale e dinamica Mathematica: variabili locali con il modulo, con, e il Blocco

Block[{expr}, 
    expr = 2 z; 
    f[z_] = expr; 
    f[7]] 

Ma se si cambia che Block ad un Module poi ritorna 2*z . Sembra non importare quali altre variabili oltre a expr localizzate. Pensavo di aver capito Modulo, Blocco e Con in Mathematica ma non posso spiegare la differenza di comportamento tra Modulo e Blocco in questo esempio.

risorse correlate:

PS: Grazie a Michael Pilat, Davorak e Bill White per seguire t Ha tracce di profumo su questa stranezza. Davorak chiarisce e arriva al nocciolo del problema qui: Why would Mathematica break normal scoping rules in Module?

risposta

6

Anche io ne sono rimasto un po 'sorpreso, ma non penso che sia un bug. Se si guarda in profondità negli esempi del reference page for Module, sotto la sezione denominata Possibili Problemi, c'è una piccola nota che dice "Variabili vengono rinominati in ambiti annidati" e fornisce il seguente esempio:

In[1]:= Module[{e = Expand[(1 + x)^5]}, Function[x, e]] 

Out[1]= Function[x$, e$1194] 

In[2]:= %[10] 

Out[2]= 1 + 5 x + 10 x^2 + 10 x^3 + 5 x^4 + x^5 

Function è un altro costrutto dell'ambito come Module, quindi x viene rinominato internamente allo x$ nell'ambito di Function, simile a quello che hai scoperto con Trace su z.

Nella tua Module definire f, Set è un altro tale costrutto scoping, e quindi z viene rinominato quando f è definito all'interno di un Module, ma non quando si trova all'interno di un Block. Seguendo il consiglio di quel esempio dalla documentazione Module, si può costruire la RHS della funzione dalle sue parti per evitare la ridenominazione lessicale del campo di applicazione nidificato:

In[3]:= Clear[f, z] 

In[4]:= Module[{expr}, 
    expr = 2 z; 
    Set @@ {f[z_], expr}; 
    f[7]] 

Out[4]= 14 

HTH!

+1

Wow, non è quello che definirei un lavoro piuttosto impegnativo ma impressionante. – dreeves

+0

Ecco perché torno a SO ogni giorno. Impara me s ** t :-). – Timo

+0

Preferisco prendere il colpo di performance inaspettato di avere expr avvolto in una conversione alfa pigra piuttosto che affrontare la sintassi incoerente. Quali sono le considerazioni sulla progettazione della lingua che stanno per giocare qui? – Davorak

2

Hai utilizzato Trace su entrambe le espressioni?

+0

Ah, intelligente! Quindi 'z_' si trasforma in' z $ _' nella versione del modulo. Quindi immagino che lo spieghi, ma continuo a non capire perché sta succedendo! Forse aggiornerò la domanda per chiedergli in particolare la stranezza. – dreeves

3

Prima di tutto, penso che tu abbia esposto un bug qui.

In secondo luogo, penso di poter offrire alcune informazioni sul perché questo sta accadendo, tenendo presente che la mia conoscenza degli aspetti interni della matematica è limitata.

un'istruzione come: f [z_]: = 2 z in forma completa è:

SetDelayed[f[Pattern[z, Blank[]]], 2 z] 

Questo imposta il DownValue [f] per:

{HoldPattern[f[z_]] :> 2 z} 

Poi più tardi quando un'espressione, come f [2], viene poi viene valutata qualcosa come segue viene preformato:

f[2] /. HoldPattern[f[z_]] :> 2 z 

il che valutare a 4. Ora, questo è tutto Po possibile perché la corrispondenza del modello sta avvenendo con Pattern [z, Blank []] dal primo blocco di codice. Funziona anche se hai impostato per sempre z su un numero. In altre parole.

z = 5; 
f[z_] := 2*z 

produce ancora le stesse downvalues ​​per f:

{HoldPattern[f[z_]] :> 2 z} 

Questo è possibile perché modello ha l'attributo HoldFirst.

L'attributo HoldFirst non è una protezione sufficiente se lo si valuta all'interno di un modulo. Esempio:

SetAttributes[tmp, HoldFirst]; 
Module[{expr}, 
expr = 2 z; 
tmp[expr] 
] 

uscite:

tmp[expr$8129] 

propongo perché HoldFirst Abilità non fornisce l'immunità a regola di riscrittura variabile del modulo che qualsiasi Modello in una regola che contiene una variabile locale hanno loro variabili modello riscritto . sym-> Simbolo [SymbolName [sym] ~~ "$"]

Module[{expr}, 
Hold[z_ -> (z; expr)] 
] 
(*Hold[z$_ -> (z$; expr$1391)]*) 

z ha essere riscritto su entrambi i lati della regola in una semplice conversione alfa.

Se la regola non contiene una variabile locale non riscrittura accade:

Module[{expr}, 
Hold[z_ -> (z)] 
] 
(*Hold[z_ -> z]*) 

Piuttosto che cercare di vedere se una variabile locale corrisponde una variabile regola viene applicata la regola di coperta sopra.

Quindi il problema è che l'espressione locale non viene valutata prima della conversione alpha. O forse sarebbe anche meglio avere expr racchiuso in una conversione alfa ponderata che sarebbe necessaria per un RuleDelayed.

Ciò non accade in Blocco perché il blocco non riscrive nessuna delle variabili locali.

Altre idee? Qualcuno vede buchi nella mia logica?

+0

Grazie mille, Davorak. Sembra che tu e Michael Pilat state affrontando lo stesso problema, giusto? – dreeves

+0

È lo stesso problema. La conversione alfa dà scope a Function, Rule, Set, SetDelayed, ma le variabili riscritte sono ancora nello spazio dei nomi globale. Immagino di essermi sbagliato sul fatto che sia un bug, ma è piuttosto fastidioso. – Davorak

Problemi correlati