qt4cg / qtspecs

QT4 specifications
https://qt4cg.org/
Other
28 stars 15 forks source link

Sequence Decomposition #1144

Closed rhdunn closed 5 months ago

rhdunn commented 5 months ago

This proposal allows sequences to be decomposed and assigned to separate variables in a single declaration within a for or let expression binding.

Given a sequence such as (1, 2, 3), the values within that sequence cannot easily be extracted. With the current version of XPath and XQuery, they need to be assigned to a temporary variable first. For example:

let $result := get-camera-point()
let $x := $result[1]
let $y := $result[2]
let $z := $result[3]
return "(" || $x || "," || $y || "," || $z || ")"

This proposal would allow this to be written more concisely as:

let ($x, $y, $z) := get-camera-point()
return "(" || $x || "," || $y || "," || $z || ")"

These are equivalent in this proposal, except that $result is not a statically known variable binding in the sequence decomposition let clause.

Note: The older syntax in XPath-NG was:

let $(x, y, z) := get-camera-point() return "(" || $x || "," || $y || "," || $z || ")"

For each variable declaration in the sequence decomposition at index N, and $expr being the result of the for/let expression, then $expr[N] is the value bound to the variable declaration as a new variable binding. If the value does not exist, an empty sequence is bound to the variable.

A sequence decomposition can be used in any for or let clause binding to decompose the items in a sequence. If the type of the for or let clause binding expression is not a sequence, an err:XPTY0004 error is raised.

Assigning the rest of a sequence

It can be useful to only extract part of a sequence or array (e.g. the heading of a table), and store the rest of the items in another variable. For example:

let $(heading, rows ...) := fn:parse-csv("test.csv")

If there are no items remaining in the sequence the result is an empty sequence.

Influences

Tuple decomposition is found in various languages such as Python, Scala, and C#. These languages also have support for tuple types.

Python has support for specifying that a variable is assigned the remaining values in the tuple.

Use Cases

There are many cases where fixed size sequences may be used such as points, complex and rational numbers, sin/cos, and mul/div. This makes extracting data from these simpler, and may also be used to aid readability by assigning descriptive names to each of the items in the sequence.

Examples

Extracting values from a sequence:

declare function sincos($angle as xs:double?) {
    math:sin($angle), math:cos($angle)
};

let $angle := math:pi()
let ($sin, $cos) := sincos($angle)
return $sin || "," || $cos
ChristianGruen commented 5 months ago

I like this proposal a lot. Isn’t it similar to the existing #37?

rhdunn commented 5 months ago

Ah yes, I was trying to look for that. Should I close these and update that discussion then?

ChristianGruen commented 5 months ago

Ah yes, I was trying to look for that. Should I close these and update that discussion then?

As you like (in https://github.com/qt4cg/qtspecs/issues/31#issuecomment-2051130690, I referenced your issue, but without adding further notes).

rhdunn commented 5 months ago

Duplicate of #37.

michaelhkay commented 5 months ago

My only reservation on this is that it endorses the idea of using a sequence as a tuple, which I'm not sure is something we want to encourage. In our own functions we always use maps/records for this kind of data structure, and personally I would encourage users to do the same.

ChristianGruen commented 5 months ago

My only reservation on this is that it endorses the idea of using a sequence as a tuple, which I'm not sure is something we want to encourage.

I think it’s very helpful for head/tail operations. It’s easier to write…

let ($head, $tail) := $sequence

.…than to build a structure in advance that wraps the head and tail into a record.

From the pedagogical point of view, I would let users decide: If decomposition will be used more often than records in practice, it rather tells us that the syntax of the latter should be improved/simplified in XPath 4.1/5.