更新 XQuery 中的变量 - 可能吗?

发布于 2024-09-25 00:56:49 字数 651 浏览 5 评论 0原文

我对 XQuery 中的变量更新有点困惑: 在[1]上说:

变量无法更新。这意味着您不能编写类似 let $x := $x+1 的内容。如果您期望 XQuery 的行为方式与过程语言(例如 JavaScript)相同,那么这条规则可能看起来很奇怪。但 XQuery 不是那种语言,它是一种声明性语言,并且在更高级别上工作。对于不同表达式的执行顺序没有任何规则(这意味着 Stylus Studio XQuery 调试器和 XSLT 调试器中显示当前执行点的黄色小三角形有时会以令人惊讶的方式运行),这意味着构造其结果将取决于执行顺序(如变量赋值)被禁止。

我想知道是否真的没有办法可靠地更新变量?也许我只是习惯了其他语言中的这些东西,但我无法真正想象/相信它;-)

[1] http://www.stylusstudio.com/xquery_flwor.html,“L代表LET”章节截图下方第二段

更新: 我必须为此添加一个问题:是否应该可以更新 if 语句中的现有变量,因为在这种情况下执行顺序是明确的?我猜你只是不允许在循环中使用类似 $x = $x+1 的东西?

I'm a little bit confused concerning variable updates in XQuery:
On [1] it says:

Variables can't be updated. This means you can't write something like let $x := $x+1. This rule might seem very strange if you're expecting XQuery to behave in the same way as procedural languages such as JavaScript. But XQuery isn't that kind of language, it's a declarative language and works at a higher level. There are no rules about the order in which different expressions are executed (which means that the little yellow triangle that shows the current execution point in the Stylus Studio XQuery debugger and XSLT debugger can sometimes behave in surprising ways), and this means that constructs whose result would depend on order of execution (like variable assignment) are banned.

I'm wondering if there is really no way to reliable update a variable? Maybe I'm just to used to those things in other languages, but I can't really imagine / believe it ;-)

[1] http://www.stylusstudio.com/xquery_flwor.html, second paragraph below the screenshots of the chapter "L is for LET"

UPDATE:
I have to add a question to this: Shouldn't it be possible to update an existing variable in an if statement because in this case the order of execution is clear? I guess you just aren't allowed to use something like $x = $x+1 in a loop?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

王权女流氓 2024-10-02 00:56:49

您正在描述不变性,这是函数式语言的一个功能。这是真的;一旦变量被设置为一个值,它就不能被设置为其他值。

不变性有很多好处。特别是,并发编程变得更加容易。

在循环的情况下,每次循环都会创建一个新变量,替换原来的变量。所以不变性仍然成立。您链接的文章对此进行了详细解释:

是否有变量正在更新
当你写类似的东西时
以下?

for $v in //video
让 $x := xs:int($v/runtime) * xdt:dayTimeDuration("PT1M")
返回 concat($v/标题, ": ", 
      持续时间的小时数($x), " 小时 ",
      分钟距持续时间($x), "分钟")

(此查询显示了运行时间
每个视频。它首先将
存储值从字符串到
整数,然后乘以一
分钟(PT1M)获取运行时间
作为持续时间,以便它可以提取
的小时和分钟组成部分
持续时间。尝试一下。)

这里变量$x有不同的
每次 XQuery 的值
环形。这感觉有点像更新。
但从技术上讲,每次
你正在创建一个新的 for 循环
具有新值的变量,而不是
为旧值分配新值
变量。

You are describing immutability, a feature of functional languages. It's true; once a variable is set to a value, it cannot be set to something else.

Immutability has many benefits. In particular, concurrent programming is made much easier.

In the case of loops, what happens is that a new variable is created each time through the loop, replacing the original one. So immutability still holds. This is explained in detail in the article you linked:

Isn't there a variable being updated
when you write something like the
following?

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")

(This query shows the running time of
each video. It first converts the
stored value from a string to an
integer, then multiplies it by one
minute (PT1M) to get the running time
as a duration, so that it can extract
the hours and minutes components of
the duration. Try it.)

Here the variable $x has a different
value each time around the XQuery for
loop. This feels a bit like an update.
Technically though, each time round
the for loop you're creating a new
variable with a new value, rather than
assigning a new value to the old
variable.

无远思近则忧 2024-10-02 00:56:49

实际上,如果您的 XQuery 处理器支持 XQuery Scripting Extension 1.0,则可以更新变量。

例如,以下示例适用于 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()

顺序函数可以进行更新。 apply 语句(以 ; 结尾的每段代码)立即应用所有更新。

如果您只想在 FLWOR 中拥有一个计数变量,您可以使用 at 关键字:

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

returns:

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

Actually, updating a variable is possible if your XQuery processor supports the XQuery Scripting Extension 1.0

E.g., the following example works in the 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()

A sequential function can do updates. The apply statement (each piece of code ending with ;) applies all updates immediately.

If you just want to have a counting variable in a FLWOR you can use the at keyword:

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

returns:

<?xml version="1.0" encoding="UTF-8"?>
1 2 3
以可爱出名 2024-10-02 00:56:49

回答关于变量的第一个问题和关于 if 语句的第二个问题。

您无法更改变量的值(这不是一个愚蠢的名称,因为它们不会变化!)。

将 XQuery 与任何复杂逻辑(以及可变变量之类的东西)结合使用的神奇之处在于递归。

Robert Harvey 提到了 for 循环的语言构造,其中变量每次都会发生变化,这是高度相关的,但这并不总能解决您的问题,除非您可以通过简单的列表迭代来实现预期的行为。您要求的是可变变量。

通过递归,你的函数会调用自己。这意味着他们可以将修改后的值传递给下一个函数调用,以代替他们已有的值。它或多或少地增加了一个可变变量,但保留了函数式语言的优点。

从程序性(步骤的顺序执行)思维方式切换到功能性(子句的同时评估)思维方式可能有点令人困惑。

递归允许实际评估的子句依赖于看起来顺序的复杂逻辑。在实践中,您只是创建一些条款,要求其他人在评估自己之前先进行评估,这并不完全相同。

这是一个愚蠢的、完全不相关且完全未经测试的示例,它展示了如何在通过递归遍历列表时“动态”修改列表,这在 for 循环中是不可能的。

请注意,变量 $patternsremaining 严格来说是一个新变量(部分基于 $patterns 计算)。无论作为参数传递到递归调用中的任何模式,都会在新函数调用中分配给 $patterns。

(: 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)
      )
};

对于使用 XSLT 和 XQuery 的核心活动(例如编写编译器),递归是我发现的唯一具有足够功能的模型。不过,真实的例子往往看起来比上面的例子更复杂。

至于 if() then () else () 语句,因为之前可能遇到相同的执行上下文(如果你是一个过程编码员,认为“堆栈变量的组合”),并且相同的表达式已经在某处被评估否则,if 语句将永远不会被再次计算,因为解释器可以根据先前的调用缓存结果。因此,您可以依赖该序列并不完全正确。它可能根本无法运行!

这是可能的,因为它内置于语言定义中,不会有会改变功能评估结果的副作用(因此这些变量不会变化)。

这种可缓存性是函数式方法的核心特征。它创造了编写高效解释器的潜力,但如果您希望能够使用可变值进行操作,则需要递归思考。

In answer to your first question about variables, and second question about if statements.

You can't change the value of a variable (a stupid name isn't it, given they don't vary!).

The magic pixie dust for using XQuery with any complex logic (and something like mutable variables) is recursion.

Robert Harvey mentioned the language construct of the for loop, in which the variable changes each time, which is highly relevant, but that can't always solve your problems unless your intended behaviour can be achieved by simple iteration of a list. What you were asking for was mutable variables.

With recursion your functions call themselves. This means they can pass in a modified value to the next function invocation in place of the value they already have. It more or less adds up to a mutable variable, but permits the benefits of a functional language to remain.

It can be a bit of a headfuzz to switch from a procedural (sequential execution of steps) way of thinking to a functional (simultaneous evaluation of clauses) way of thinking.

Recursion allows the clauses which are actually evaluated to depend on complex logic which kind of looks sequential. In practice you're simply creating clauses which demand others to be evaluated before they can evaluate themselves, which is not quite the same thing.

Here is a stupid, entirely irrelevant and totally untested example which shows how a list can be modified 'on the fly' as it is traversed by recursion, something which is impossible in a for loop.

Note the variable $patternsremaining is strictly a new variable (calculated partly based on $patterns). Whatever patterns are passed as an argument into the recursive call are assigned to $patterns within the new function invocation.

(: 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)
      )
};

For hardcore activities with XSLT and XQuery (e.g. writing compilers) recursion is the only model I've found with sufficient power. Real examples have a tendency of looking even more complicated than the one above, though.

As regards the if() then () else () statement, because it's feasible that the same execution context (if you're a procedural coder think 'combination of stack variables') was encountered before, and the same expression was evaluated already somewhere else, then the if statement will NEVER be evaluated again, because the interpreter can cache the result, based on the previous invocation. It's therefore not strictly true that you can rely on the sequence. It may not be run at all!

This is possible because it is built into the language definition that there can be no side effects which would change the result of a functional evaluation (hence those variables which don't vary).

This cacheability is a central feature of the functional approach. It creates the potential for highly efficient interpreters to be written, but it requires you to think recursively if you want to be able to operate with mutable values.

凉城凉梦凉人心 2024-10-02 00:56:49

不,您无法更新变量。如果您不能依赖执行顺序,那么这样做又有什么意义呢?

当然,即使没有可更新的变量,您也可以使用递归函数执行几乎所有操作,包括具有递增变量的“循环”。这是否有效或好主意是另一回事。我曾经使用递归模板在 XSLT(也有不可更新的变量)中实现了 sqrt()...

No, you can't update a variable. If you can't rely on the order of execution, how would doing so make sense anyways?

Of course, even without updatable variables, you can do pretty much everything, including "loops" with incrementing variables, using a recursive function. Whether this is efficient or a good idea is another story. I once implemented sqrt() in XSLT (which also has non-updatable variables) using a recursive template...

拧巴小姐 2024-10-02 00:56:49

相信它。

在这方面,XQuery 就像一种函数式编程语言。您不想从函数/数学角度更改已计算的计算值。此外,数据是不可变的,不能改变状态,因此该语言可用于构建高并发应用程序。 Erlang 是为高并发而构建的语言的“好”例子。在一些命令式语言(例如 Java)中也使用不变性来实现高并发。

就像在任何其他函数式语言中一样,您始终可以确保“评估”您的“expr”,然后使用副本进行所需的更改。

请注意,我并不是说 XQuery 是一种很好的函数式编程语言。查看 erlang 的示例,了解良好的函数式语言和提供良好性能的实现。

Believe it.

XQuery is like a functional programming language in this regard. You don't want to change the value of already calculated computation from a functional/mathematical perspective. Also, data is immutable and cannot change state so the language can be used to build high concurrency applications. Erlang is a "good" example of a language built for high concurrency. Immutability is also used in some imperative languages such as Java for high concurrency.

Just like in any other functional language you can always ensure you "eval" your "expr" and then make the required changes with a copy.

Note that I am not saying XQuery is a good functional programming language. Have a look at erlang for an example of a good functional language and implementation that provides good performance.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文