2010-04-29 9 views
7

Come è stato sottolineato in un recente post l'ambito non funziona come previsto all'interno del modulo.Perché Mathematica interromperà le normali regole di scoping nel modulo?

Un esempio da quel filo è:

Module[{expr}, 
expr = 2 z; 
    f[z_] = expr; 
    f[7]] 
(*2 z*) 

Ma il seguente funziona quasi come previsto.

Quale considerazione del design linguistico ha fatto scegliere a wolfram questa funzionalità?

Modifica: vedere il primo commento di Jefromi Ho cambiato z da variabile locale a non e ho dimenticato di modificare l'output. Non ha alcun effetto sul problema.

Edit2: Il punto di Michael Pilat sembra essere che Block e Module hanno funzioni diverse. Penso di capire il suo punto, ma penso che sia ortogonale alla mia domanda. Quindi ecco un aggiornamento.

posso utilizzare il seguente codice a livello globale in un notebook:

expr = 2 z; 
f[z_] = expr; 
f[7] 
(*output: 14*) 

Ma quando metto lo stesso blocco di codice in un modulo e rendere locale expr produce un output diverso.

Clear[f]; 
Module[{expr}, 
expr = 2 z; 
f[z_] = expr; 
f[7]] 
(*output: 2z*) 

Se si traccia il modulo di cui sopra chiamare si scopre che Set [f [z_], espr] viene riscritto per impostare [f [z $ _, espr]. Ora questa trasformazione z-> z $ si verifica sia su lhs che su rhs del Set. Succede comunque prima che venga valutato expr, il che provoca un risultato diverso da ottenere a livello globale.

La trasformazione z-> z $ sembra avvenire solo quando il rh ha un simbolo locale alla chiamata del modulo.

Perché Mathematica ha scelto di modificare questa sintassi in una chiamata di Modulo? Quali sono i compromessi sul design della lingua/implementazione qui che hanno preso questa decisione.

+0

Quale versione di mathematica stai usando? Il primo ti dà davvero z del modulo locale ('z $ 1776') invece di solo' 2z' (che è quello che ottengo, usando la versione 6.0.0). – Cascabel

+0

Oppure la z locale creata dalla corrispondenza del modello? – Cascabel

+1

Da Trace, sembra che Mathematica decida che poiché c'è una variabile locale sul RHS del set, userà una variabile locale per il pattern ('f [z $ _] = expr $ 64'). In tutti gli altri casi a cui posso pensare, quando l'RHS non contiene una variabile locale, usa l'atteso 'f [z_] = ...'. Forse c'è qualche ragionevole caso di valutazione in cui questo comportamento ha un senso, ma io certamente non riesco a pensarci. +1, e spero che qualcuno riesca a rispondere. – Cascabel

risposta

2

Secondo the documentation, Module ha attributo HoldAll, che fa sì che tutto all'interno del Module di rimanere in uno stato non valutata, in modo che il expr non viene analizzato per 2 z prima expr è assegnato a f[z_].

Avvolgere il secondo argomento a Module in Evaluate sembra risolvere il problema:

In[1]:= Module[{expr}, Evaluate[expr = 2 z; 
    f[z_] = expr; 
    f[7]]] 

Out[1]= 14 

Inoltre, utilizzando Block invece di Module opere:

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

Out[2]= 14 
+0

Utilizzando Evaluate è stato eseguito expr una variabile globale anziché locale. – Davorak

5

Penso che la risposta è piuttosto semplice, ma sottile: Module è un costrutto di ambito lessicale e Block è un costrutto di ambito dinamico.

Il Blocks Compared With Modules esercitazione della documentazione discute la distinzione:

Quando si utilizza scoping lessicale, le variabili sono considerate come locale per una particolare sezione del codice di un programma.In ambito dinamico, i valori delle variabili sono locali in una parte della cronologia di esecuzione del programma. In linguaggi compilati come C e Java, c'è una netta distinzione tra "codice" e "cronologia dell'esecuzione". La natura simbolica di Mathematica rende questa distinzione un po 'meno chiara, poiché il "codice" può in linea di principio essere costruito dinamicamente durante l'esecuzione di un programma.

Ciò che Module[vars, body] fa è trattare la forma del corpo di espressione nel momento in cui il modulo viene eseguito come "codice" di un programma Mathematica. Quindi, quando uno qualsiasi dei vars appare esplicitamente in questo "codice", è considerato locale. Block[vars, body] non osserva la forma del corpo dell'espressione. Invece, durante la valutazione del corpo, il blocco utilizza i valori locali per i vars.

offre questa ridotta esempio:

In[1]:= m = i^2 

Out[1]= i^2 

(* The local value for i in the block is used throughout the evaluation of i+m. *) 
In[2]:= Block[{i = a}, i + m] 

Out[2]= a + a^2 

(* Here only the i that appears explicitly in i+m is treated as a local variable. *) 
In[3]:= Module[{i = a}, i + m] 

Out[3]= a + i^2 

Forse il punto chiave è quello di rendersi conto che Module sostituisce tutte le istanze di i nel corpo modulo con una versione localizzata (ad esempio, i$1234) lessicalmente, prima del viene valutato qualsiasi componente del modulo.

Pertanto, il corpo del modulo effettivamente valutato è i$1234 + m, quindi i$1234 + i^2, quindi a + i^2.

Nulla è interrotto, Block e Module hanno lo scopo di comportarsi diversamente.

+0

Questo è vicino a quello che ho risposto nell'ultima domanda. Il punto di puntare lessicalmente a qualcosa è che puoi rendere alcune variabili locali e lasciare tutto il resto invariato. Il modulo non lascia tutto il resto invariato. In che modo la modifica della sintassi disponibile serve allo scopo del modulo? Guarda la Traccia dei Moduli sopra uno con f [z _] = expr e uno con f [z_] = . Il primo ha z riscritto come z $ e nella successiva z rimane invariato. Perché il modulo interagisce con l'ambito interno aggiuntivo in questo modo? C'è qualche criterio di progettazione linguistica che mi manca? – Davorak

+0

Se il modulo non ha riscritto z come z $ nel caso successivo, il set di f [z_] avrebbe funzionato come sarebbe fuori dal lato di un'istruzione di modulo e come si aspetterebbe che funzionasse. Anche grazie. – Davorak

+0

Nel caso in cui non fosse chiaro, non capisco come si suppone che l'esempio si applichi all'esempio che ho fornito poiché tutti gli Insiemi nel mio esempio si verificano nell'istruzione Module e la vostra no. – Davorak

Problemi correlati