Domanda

Mi piacerebbe controllare e manipolare il codice di procedure arbitrarie Perl (ottenuto da coderefs) in Perl. Esiste uno strumento / modulo / libreria per questo? Qualcosa di simile a B :: Concise , la differenza che B :: Concise stampare il codice a uscita, ma mi piacerebbe di ispezionare a livello di codice.

Mi piacerebbe utilizzarlo in questo modo. Dato un F rifcodice, che si chiama es. con 10 argomenti:

$ret = &$F(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10);

Mi piacerebbe creare una funzione F1, st.

&$F(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10) == 
  &$F1(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10)*
  &$C(x2, x3, x4, x5, x6, x7, x8, x9, x10)

che è "fattore" in due parti, in cui il secondo non dipende x1 e il primo è più semplice possibile (presumo F è costruito come un prodotto enorme).

L'applicazione che voglio questo per è l'ottimizzazione dei Metropolis campionamento algoritmo - suppongo che sto campionamento il p(x1 | x2 = X1, x3 = X3, ...) = f(x1, x2, x3, ...) distribuzione. L'algoritmo in sé è WRT invariante. fattori moltiplicativi costanti, e altre variabili non cambiano attraverso gli algoritmi, quindi la parte non a seconda x1 (es. $c dall'alto) non devono essere valutate affatto).

La probabilità congiunta potrebbe avere ad esempio. il seguente modulo:

  p(x1, x2, x3, x4, x5) = g1(x1, x2)*g2(x2, x3)*g3(x3, x4)*g4(x4, x5)*g5(x4, x1)*g6(x5, x1)

Ho anche considerare la costruzione p come oggetto consistente dei fattori con annotazioni di cui variabili fa un fattore particolare dipendono. Anche questo trarrebbe vantaggio dal codice introspezione (determinazione delle variabili automaticamente).

È stato utile?

Soluzione

Per l'introspezione di optrees è di solito utilizzato la famiglia B di moduli.

Dato un $cv codice di riferimento, innanzitutto creare un oggetto B per questo:

my $b_cv = B::svref_2object($cv);

Ora è possibile chiamare i vari metodi documentati in B da quello di recuperare le varie cose dal optree.

Utilizzando solo l'introspezione optree si può già realizzare cose incredibili. Per un esempio abbastanza avanzata di questo Vedi DBIx::Perlish .

Non avviene anche per essere un B::Generate modulo, che permette la costruzione di nuove optrees che fare quello che vuoi , o per manipolare optrees esistenti. Tuttavia, B::Generate non è maturo come si potrebbe sperare, e c'è un sacco di funzioni mancanti e un bel paio di bug.

creazione optree reale e la manipolazione di solito è meglio farlo utilizzando Perl C api, come documentato in perlapi , perlguts e perlhack , tra gli altri. Probabilmente dovrete imparare un po ' XS pure, per esporre le funzioni di manipolazione optree che hai scritto verso lo spazio perl, ma questa è la parte più semplice davvero.

Imprese optrees (non necessariamente basati su altri optrees esistenti che vengono introspected) sembra essere diventato un po 'popolare di recente, soprattutto perché Syntax Plugins sono stati aggiunti al nucleo in perl 5.12.0. Si possono trovare vari esempi come Scope::Escape::Sugar su CPAN.

Tuttavia, si tratta di optrees del Perl è ancora un po 'laborioso e non esattamente principiante-friendly. Non dovrebbe essere necessario per qualsiasi delle cose più arcane. Qualcosa di simile utilizzando B::Deparse->new->coderef2text($cv) e poi magari pressare leggermente con il codice sorgente valutata è davvero quanto vorrei andare con optree introspezione da puro spazio-perl.

Si potrebbe desiderare di fare un passo indietro un po 'e spiegare il vero problema che si sta cercando di risolvere. Forse c'è una soluzione molto più semplice che non comporta scherzi con optrees a tutti.

Altri suggerimenti

Data la tua domanda ribadito -. Credo che ciò che si dovrebbe fare qui, invece di cercare di coderefs Munge, è quello di ritardare avere una rifcodice più a lungo possibile

  1. Crea un oggetto che rappresenta un'istanza della computazione.
  2. Scrivi i metodi su questo oggetto necessario per valutare il valore del calcolo. No Codegen, basta farlo la strada più lunga lenta. Questo è solo per darvi una base di codice per i prossimi passi che è facilmente testati e, auspicabilmente, di facile comprensione.
  3. test di scrittura al fine di garantire la correttezza di quello che hai fatto al punto 2. (Swap questo prima Fase 2, se siete quel tipo di persona.)
  4. attuare ciò che si sta chiedendo a questa domanda, scrivendo i metodi per trasformare un oggetto di calcolo in uno nuovo che rappresenta una forma più ottimizzato dello stesso calcolo. Utilizzare i test per garantire che i calcoli ancora dare il giusto risultato dopo l'ottimizzazione.
  5. codice scrivere che prende un oggetto computazione, e genera un sub (sia per eval stringa o utilizzando B) che effettua che il calcolo. Utilizzare i test per garantire che i calcoli ancora dare il giusto risultato dopo che sono stati compilati.

Passaggio facoltativo per inserire ovunque tra 2 e 5:

  • Scrivi po 'di zucchero sintattico (probabilmente usando overload, ma altri strumenti sono possibili anche) per farvi costruire "oggetti di calcolo" utilizzando espressioni piacevole-osservare che ricordano il calcolo in sé, invece di un sacco di costruttori di oggetti.

Perl 5 non consente di manipolare il bytecode al volo del genere, ma è possibile creare funzioni anonime. Se ho capito correttamente il vostro esempio, e dubito che faccio, si dispone già di due funzioni che vengono fa riferimento $f1 e $c, e si desidera creare un nuovo $f di riferimento che contiene i risultati dei primi due moltiplicato per l'altro. Questo è semplice:

my $f = sub { $f1->(@_) * $c->(@_[1 .. 9]) };

$f->(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

Si noti l'uso dell'operatore freccia piuttosto che il & per dereference i coderefs. Questo stile è molto più comune (e, a mio parere più leggibile).

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top