In response to the question of Michael SpMcQ in the telcon of today regarding binding non-local variables

In the telcon of today a part of discussion evolved around how non-local variable bindings are bound to functions, and partial functions in particular. Michael correctly mentioned that if a function body contains a variable $NAME and a global variable $NAME exists, that it is shadowed and henceforth not accessible.

However, I believe that the text as currently written formally creates a set of non-local variable bindings regardless whether or not the body of a function may shadow such variable. I don't think there is a problem here, but it is an interesting edge case and implementations can use this information for optimizations.

More interestingly, consider the case that I was trying to bring under attention. 

(: shadow and non-shadow combined  :)
let $p := 10 return (let $p := function() {$p + 1} return $p() * 2)

(: in a function :)
let $p := 10
return function($p, $q) { $p * $q }

(: with pfa :)
let $p := 10,
$f := function($p, $q) { $p * $q }
return $f(?, $p)

1) In the first trivial example, the $p inside the zero-arity function is not shadowed. The second $p after "return" is shadowed, however and will return the inner $p which is bound to the zero-arity function. The expression will return 22

2) In the second example, the function body cannot access the variable $p (with value 10) because it is shadowed, as a result it has no effect on the body of the function, though technically it will be part of the non-local variable bindings (effectively making the non-locals the group of ($p) and the locals the group of ($p, $q), but both $p in either group are not the same).

3) In the third example, which is what I tried to get at w.r.t. to the current proposal for item 5.1.a., we have a non-local binding $p set to 10, $f is not part of the non-local bindings (recursive variables are not allowed), and the function creates a closure with local bindings ($p, $q), which are its arguments, and non-local bindings $p. The expression returns a partially applied function with its second argument set to $p, which is 10. This does *not* shadow the local variable binding $p even though it carries the same identifier. Let's call the result of this expression $PFA. Then $PFA(22) will return 210, not 100. The latter could happen if the current text remained in place and was taken too literally.

In retrospect, this example, and Michael's question, touches directly to the question at hand as to how DC and SC are attached (or not). Suppose $p in the last example is attached to "." (the context item). Does it then *contain* that context item because it is bound at the moment of the partial function application, or does it become a chameleon and it is essentially a reference to the DC's current item that is in scope upon function invocation?

In other words, let's change the third example, assume an existing context item (which may or may not throw, I don't know, if there is none):

(: with pfa, version 2 :)
let $p := .,
$f := function($p, $q) { $p * $q }
return $f(?, $p)

Let's assume we use XQuery or XSLT to bind this result to the variable $PFA, say with xsl:variable at global scope and that at global scope the context item is xs:integer(21), and then we use it like this:

for $i in 1 to 3 return $PFA(2)

Do we now get a sequence of (42, 42, 42) or a sequence of (2, 4, 6)? >From earlier discussions, I know it should be the former. This changes, however, if we change the definition once more:

(: with pfa, version 3 :)
let $p := .,
$f := function($p, $q) { . * $p * $q }
return $f(?, $p)

and the same elsewhere: for $i in 1 to 3 return $PFA(2)

Now the function invocation should return the a different sequence. However, we do not allow the context item to appear at the body of the function because in 5.b.v.A we say that context size, position and item are absent. That does, however, not lift us from the burden to define what happens with DC as it does contain other things, like default collections, collation uri, environment variables. It would be interesting to think about what happens when $PFA is carried over to a different execution scope, i.e. as parameter for fn:transform or xsl:evaluate.

I don't think we say anything explicit about the latter.

For fun and the like, here's a complete example in XSLT 3.0 that tries out these concepts, deliberately convoluting the code by re-using the variable names as much as possible:

<xsl:variable name="pfa" select="
            42!
           (let $p :=
            let $p := .
            return
               let $p := $p
               return 
                  let $f := function($p, $q) { $p * $q }
                  return $f(?, $p)
            return $p)" />

<xsl:template match="/" name="xsl-initial-template">
    <xsl:sequence select="(1 to 10)!$pfa(.)" />
</xsl:template>

This returns: 42 84 126 168 210 252 294 336 378 420, I think that is correct.

Cheers,
Abel

Received on Wednesday, 10 February 2016 01:12:07 UTC