- From: Michael Kay <mike@saxonica.com>
- Date: Wed, 10 Dec 2025 10:24:23 +0000
- To: Dimitre Novatchev <dnovatchev@gmail.com>
- Cc: public-xslt-40@w3.org
- Message-Id: <D23A967C-DA9D-4E0E-A20C-BD13AB57FA8F@saxonica.com>
> On 9 Dec 2025, at 19:59, Dimitre Novatchev <dnovatchev@gmail.com> wrote:
>
> > > I currently have a gut feeling that many of the use cases could be satisfied by a simple function such as
> > >
> > > generate-sequence($initial-state, $step)
> > >
> > > returning a sequence of states, where $step is a function that computes the next state from the current state.
> >
> > This reminds me a lot of the proposal made by Reece two years ago [1]. Several interesting questions had been asked in this thread, for example if "count(generate-> sequence(...))" would work, or, more generally, if the function would introduce a new value type that has no fixed size.
> >
> > [1] https://github.com/qt4cg/qtspecs/issues/708
>
>
> A few quick observations:
>
> The cited issue (#708) proposes that each value returned is an `item()`. And this excludes a value being a sequence. By definition, any value in a generator's yield can be a sequence. Thus no limitations and no sacrifices.
I'm proposing that the "state" should be an item. By using a map to hold the state, and having a method get-value() or get-current() on the state object, there's no difficulty yielding a series of arbitrary values. The value can be computed from the state in any way you like.
For example, `generate-sequence(1, fn($n){$n + 1}) => array:build(fn{$n}{1 to $n })` would yield the unbounded array [1, (1,2), (1,2,3), (1,2,3,4), ... ]
We could perhaps label selected functions and operators as being "pipelined", as a signal to users and implementors that there is a reasonable expectation of lazy evaluation, and of being able to process unbounded sequences/arrays.
> This seems problematic: Passing around and mixing/processing different instances of different intermediate results of several generate-sequence() instructions. With Generators this is done naturally. And "all these functions" are the "mixers" that produce any imagined, and even unanticipated processing and result.
Sorry, I don't understand the problem.
There's an issue, of course, that the "state" object isn't strongly typed. It would be great to have generics so the function signature becomes
generate-sequence($init as <STATE>, $step as fn(<STATE>) as <STATE>) as <STATE>*
but of course that's a completely orthogonal idea.
We could amend the proposal so that the STATE object must be a record, and must have a get-value() method. But I think that complicates it unnecessarily: for example it would add complexity to my example that generates an infinite sequence of random numbers.
I would instead suggest that the return type of $step be <STATE>? with an empty sequence denoting that the sequence generation is finished.
I don't see any difficulty using existing functions and operators (such as fn:filter or FLWOR expressions) to process the sequence produced by generate-sequence(). There is no need for new functions that reproduce the functionality of the ones we already have.
The key thing is, though: I would like to see a set of use cases, forming a requirements statement for this feature, so that we can assess proposals like this one to see to what extent they meet the requirement.
Michael Kay
Saxonica
Received on Wednesday, 10 December 2025 10:24:40 UTC