Pregunta

Me gustaría inspeccionar y manipular código de procedimientos Perl arbitrarias (conseguido por coderefs) en Perl. ¿Existe una herramienta / módulo / biblioteca para que? Algo similar a B :: Concisa , excepto que B :: concisa imprime el código en la salida, pero me gustaría para inspeccionarlo mediante programación.

Me gustaría utilizar de esta manera. Dado un F coderef, que se llama por ejemplo. con 10 argumentos:

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

Me gustaría crear un F1 función, 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)

que es "factor" en dos partes, en el que el segundo no depende de x1 y la primera es tan simple como sea posible (Asumo F se construye como un producto enorme).

La aplicación quiero esto para es la optimización de Metropolis muestreo algoritmo - supongo que estoy muestreo de la p(x1 | x2 = X1, x3 = X3, ...) = f(x1, x2, x3, ...) distribución. El algoritmo en sí es invariante WRT. factores constante multiplicativa, y otras variables no cambian a través de los algoritmos, por lo que la parte no dependiendo de x1 (es decir. $c desde arriba) no necesitan ser evaluadas en absoluto).

La probabilidad conjunta podría tener, por ejemplo. la forma siguiente:

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

Yo también consideran la construcción de p como un objeto que consta de los factores con anotaciones de las variables que lo hace un factor particular depende. Incluso esto se beneficiaría de la introspección de código (determinación de las variables de forma automática).

¿Fue útil?

Solución

En la introspección de optrees se utiliza generalmente la familia B de módulos.

Dado un $cv referencia de código, crear primero un objeto B para que:

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

Ahora usted puede llamar a los diversos métodos documentados en B en que para recuperar varias cosas de la optree.

Usando sólo la introspección optree ya se puede lograr cosas increíbles. Ver DBIx::Perlish para un ejemplo avanzado bastante de esto.

Hay también pasa a ser un B::Generate módulo, que permite la construcción de nuevas optrees que hacer lo que quiera o para manipular optrees existentes. Sin embargo, B::Generate no está tan maduro como es de esperar, y hay una gran cantidad de características que faltan y unos cuantos insectos.

optree creación real y la manipulación es generalmente hacen mejor uso de la API C de Perl, como se documenta en perlapi , perlguts y perlhack , entre otros. Es probable que tenga que aprender algo de XS así, para exponer las funciones de manipulación de optree que escribió de vuelta al espacio Perl, pero esa es la parte fácil realmente.

optrees de construcción (no necesariamente basados ??en otros optrees existentes que se están introspección) parece haberse convertido en algo popular recientemente, sobre todo porque Syntax Plugins se han añadido a la base en Perl 5.12.0. Usted puede encontrar varios ejemplos como Scope::Escape::Sugar en CPAN.

Sin embargo, se trata de optrees de Perl es aún un poco más incómoda y no precisamente fácil para principiantes. No debería ser necesario para cualquiera de las mayoría de las cosas arcanas. Algo así como el uso de B::Deparse->new->coderef2text($cv) y luego tal vez mangling muy poco con el código fuente evaluado es realmente por lo que yo quiero ir con la introspección optree desde el espacio puro Perl.

Es posible que desee dar un paso atrás un poco y explicar el problema real que estamos tratando de resolver. Tal vez hay una solución mucho más simple que no implica jugar con optrees en absoluto.

Otros consejos

Dada su pregunta replanteado -. Creo que lo que debe hacer aquí, en lugar de tratar de coderefs munge, es retrasar tener un coderef el mayor tiempo posible

  1. Crear un objeto que representa una instancia de su cálculo.
  2. Escribir los métodos de este objeto es necesario para evaluar el valor de la computación. Sin codegen, sólo lo hacen el camino largo y lento. Esto es sólo para darle una línea de base de código para los próximos pasos que se probaron con facilidad y es de esperar de fácil comprensión.
  3. pruebas de escritura para asegurar la exactitud de lo que hizo en el paso 2. (SWAP Este antes del paso 2 si eres ese tipo de persona.)
  4. Implementar lo que preguntas acerca de esta cuestión, escribiendo métodos para transformar un objeto de cálculo en uno nuevo que representa una forma más optimizada del mismo cálculo. Use sus pruebas para asegurar que los cálculos todavía dan el resultado correcto después de la optimización.
  5. Escribir código que toma un objeto de cálculo, y genera un sub (ya sea por eval cuerda o usando B) que lleva a cabo que la computación. Use sus pruebas para asegurar que los cálculos todavía dan el resultado correcto después de que han sido compilados.

Paso opcional para insertar en cualquier lugar entre 2 y 5:

  • Escribir un poco de azúcar sintáctica (probablemente utilizando overload, pero otras herramientas son posibles también) para que pueda construir "objetos de cálculo" usando expresiones agradables de aspecto que se asemejan a la computación en sí, en lugar de montones y montones de objetos constructores.

Perl 5 no permiten manipular el código de bytes sobre la marcha de esa manera, pero se pueden crear funciones anónimas. Si entiendo correctamente tu ejemplo, y dudo que lo haga, ya tiene dos funciones que se están referenciados por $f1 y $c, y desea crear un nuevo $f referencia que contiene los resultados de las dos primeras multiplicado por la otra. Esto es simple:

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

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

Tenga en cuenta el uso del operador de flecha en lugar de la & a eliminar la referencia al coderefs. Este estilo es mucho más común (y en mi opinión más legible).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top