2010-09-23 9 views
5

estoy un poco confundido respecto a cambios en variables XQuery: En [1] se dice:Actualización de variables en XQuery: posible o no?

Las variables no se pueden actualizar. Esto significa que no puede escribir algo como let $ x: = $ x + 1. Esta regla puede parecer muy extraña si espera que XQuery se comporte de la misma manera que los lenguajes de procedimiento como JavaScript. Pero XQuery no es ese tipo de lenguaje, es un lenguaje declarativo y funciona en un nivel superior. No existen reglas sobre el orden en que se ejecutan las diferentes expresiones (lo que significa que el pequeño triángulo amarillo que muestra el punto de ejecución actual en el depurador XSuery Stylus Studio XQuery a veces puede comportarse de manera sorprendente), y esto significa que las construcciones cuya el resultado dependerá del orden de ejecución (como la asignación de variables) están prohibidos.

Me pregunto si realmente no hay manera de actualizar de forma confiable una variable? Tal vez estoy acostumbrado a esas cosas en otros idiomas, pero no puedo imaginarlo/creerlo ;-)

[1] http://www.stylusstudio.com/xquery_flwor.html, segundo párrafo debajo de las capturas de pantalla del capítulo "L es para DEJAR"

aCTUALIZACIÓN: tengo que añadir una pregunta a este: ¿no debería ser posible actualizar una variable existente en una sentencia if porque en este caso el orden de ejecución está claro? ¿Supongo que no puedes usar algo como $ x = $ x + 1 en un bucle?

+0

Tengo que agregar una pregunta a esto: ¿No debería ser posible actualizar una variable existente en una instrucción if porque en este caso el orden de ejecución es claro? ¿Supongo que no puedes usar algo como $ x = $ x + 1 en un bucle? –

Respuesta

5

Usted está describiendo la inmutabilidad, una característica de functional languages. Es cierto; una vez que una variable se establece en un valor, no se puede establecer en otra cosa.

La inmutabilidad tiene muchos beneficios. En particular, concurrent programming es mucho más fácil.

En el caso de los bucles, lo que sucede es que una nueva variable se crea cada vez que pasa el bucle, reemplazando la original. Entonces, la inmutabilidad aún se mantiene. Esto se explica en detalle en el artículo se conectó:

no hay una variable que está siendo actualizado cuando se escribe algo así como el siguiente?

for $v in //video 
let $x := xs:int($v/runtime) * xdt:dayTimeDuration("PT1M") 
return concat($v/title, ": ", 
     hours-from-duration($x), " hour(s) ", 
     minutes-from-duration($x), " minutes") 

(Esta consulta muestra el tiempo de funcionamiento de cada video. En primer lugar, convierte la valor almacenado de una cadena a un entero , a continuación, lo multiplica por uno minutos (PT1M) para obtener el tiempo de funcionamiento como la duración, de modo que pueda extraer las horas y minutos componentes de la duración. Pruébalo.)

Aquí la variable $ x tiene un valor diferente cada vez alrededor de la XQuery para bucle.Esto se siente como una actualización. Aunque técnicamente, en cada vuelta el bucle for está creando una nueva variable con un nuevo valor, en lugar de asignando un nuevo valor a la variable anterior.

+0

Gracias, supongo que no me di cuenta de que esto no es solo un lenguaje de procedimiento, sino uno funcitonal. –

+0

Agregué una pregunta más arriba, ¿alguien tiene una pista sobre eso? :-) –

+0

@stefan: Ver mi edición. –

0

No, no puede actualizar una variable. Si no puede confiar en el orden de ejecución, ¿cómo hacerlo tendría sentido de todos modos?

Por supuesto, incluso sin variables actualizables, puede hacer casi todo, incluso "bucles" con variables incrementales, utilizando una función recursiva. Si esto es eficiente o una buena idea es otra historia. Una vez implementado sqrt() en XSLT (que también tiene variables no actualizables) usando una plantilla recursiva ...

+0

Bueno, tienes razón, realmente no tiene sentido en este caso ;-) –

0

Si bien las variables no se pueden actualizar, puede definir una segunda variable con el mismo nombre, en cuyo caso cualquier referencia a esa variable con el alcance de su enlace se vinculará a la variable posterior con el ámbito más pequeño.

Así

let $x := $x + +1 
return $x 

significa

let $x_2 := $x_1 +1 
return $x_2 
0

creas.

XQuery es como un lenguaje de programación funcional en este sentido. No desea cambiar el valor del cálculo ya calculado desde una perspectiva funcional/matemática. Además, los datos son inmutables y no pueden cambiar de estado, por lo que el lenguaje puede usarse para crear aplicaciones de alta concurrencia. Erlang es un "buen" ejemplo de un lenguaje creado para alta concurrencia. La inmutabilidad también se usa en algunos lenguajes imperativos, como Java para la concurrencia alta.

Al igual que en cualquier otro lenguaje funcional, siempre puede asegurarse de "evaluar" su "expr" y luego realizar los cambios necesarios con una copia.

Tenga en cuenta que no estoy diciendo que XQuery sea un buen lenguaje de programación funcional. Echa un vistazo a erlang para ver un ejemplo de un buen lenguaje funcional e implementación que proporciona un buen rendimiento.

6

En realidad, la actualización de una variable es posible si su procesador XQuery soporta el Scripting de XQuery Extensión 1.0

Por ejemplo, el siguiente ejemplo funciona en el Zorba Sandbox:

declare namespace an = "http://zorba.io/annotations"; 

declare %an:sequential function local:fib(){ 
    variable $a as xs:integer := 0; 
    variable $b as xs:integer := 1; 
    variable $c as xs:integer := $a + $b; 
    variable $fibseq as xs:integer* := ($a, $b); 
    while ($c < 100) { 
    $fibseq := ($fibseq, $c); 
    $a := $b; 
    $b := $c; 
    $c := $a + $b; 
    } 
    $fibseq 
}; 

local:fib() 

Una función secuencial puede hacer cambios . La instrucción apply (cada fragmento de código que termina con ;) aplica todas las actualizaciones de inmediato.

Si lo que desea es tener una variable de conteo en un FLWOR puede utilizar el at palabra clave:

for $item at $x in ("a","b","c") 
return $x 

devuelve:

<?xml version="1.0" encoding="UTF-8"?> 
1 2 3 
2

En respuesta a su primera pregunta acerca de las variables, y el segundo pregunta acerca de si las declaraciones.

No puede cambiar el valor de una variable (un nombre estúpido no lo es, dado que no varían).

El polvo de duende mágico para usar XQuery con cualquier lógica compleja (y algo así como variables mutables) es la recursión.

Robert Harvey mencionó el constructo del lenguaje del bucle for, en el cual la variable cambia cada vez, que es muy relevante, pero que no siempre puede resolver sus problemas a menos que su comportamiento intencionado se pueda lograr mediante la simple iteración de una lista . Lo que estabas pidiendo era variables mutables.

Con recursion sus funciones se llaman a sí mismas. Esto significa que pueden pasar un valor modificado a la siguiente invocación de función en lugar del valor que ya tienen. Más o menos se suma a una variable mutable, pero permite que permanezcan los beneficios de un lenguaje funcional.

Puede ser un poco arriesgado pasar de una forma de pensar procedimental (ejecución secuencial de pasos) a una forma de pensar funcional (evaluación simultánea de cláusulas).

La recursividad permite que las cláusulas que se evalúan realmente dependan de una lógica compleja que se ve secuencial. En la práctica, simplemente estás creando cláusulas que exigen que otros sean evaluados antes de que puedan evaluarse a sí mismos, lo cual no es exactamente lo mismo.

Aquí hay un ejemplo estúpido, completamente irrelevante y totalmente no probado que muestra cómo una lista puede ser modificada 'sobre la marcha' ya que es atravesada por recursión, algo que es imposible en un bucle for.

Tenga en cuenta que la variable $ patternsremaining es estrictamente una nueva variable (calculada en parte en función de $ patrones). Los patrones que se pasan como un argumento en la llamada recursiva se asignan a $ patrones dentro de la nueva invocación de función.

(: Here $patterns looks like <pattern match="something" replace="else" /> :) 
declare function local:transform($text as text(), $patterns as element(pattern)*) { 
    if(not($patterns)) then 
     $text 
    else 
     let $patternsremaining := $patterns[position() > 1], 
      $modifiedtext := replace($text, $pattern/@match, $pattern/@replace) 
     return 
     if($local:language="French" and not($patterns[@match='le'])) then (
      local:transform($modifiedtext, ($patternsremaining, <pattern match="Londres" replace="London" />)) 
    ) 
     else(
     local:transform($modifiedtext, $patternsremaining) 
    ) 
}; 

Para las actividades del hardcore con XSLT y XQuery (por ejemplo, los compiladores de escritura) recursividad es el único modelo que he encontrado con suficiente potencia. Sin embargo, los ejemplos reales tienden a parecer incluso más complicados que el anterior.

En cuanto a la instrucción if() then() else(), porque es factible que el mismo contexto de ejecución (si es un codificador de procedimientos piense 'combinación de variables de pila') se haya encontrado antes, y la misma expresión ya se evaluó en otro lugar, entonces la declaración if NUNCA se evaluará nuevamente, porque el intérprete puede almacenar en caché el resultado, en función de la invocación anterior. Por lo tanto, no es estrictamente cierto que puede confiar en la secuencia. ¡No puede ejecutarse en absoluto!

Esto es posible porque está integrado en la definición del lenguaje que no puede haber efectos secundarios que puedan cambiar el resultado de una evaluación funcional (de ahí las variables que no varían).

Esta cacheabilidad es una característica central del enfoque funcional. Crea el potencial de escribir intérpretes altamente eficientes, pero requiere que piense de forma recursiva si desea poder operar con valores variables.

+0

Reacción rápida: "variable" no es un nombre estúpido a menos que creas que también es un nombre estúpido en Algebra. –

Cuestiones relacionadas