Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue 80: fn:iterate-while (before: fn:while) #210

Merged
merged 5 commits into from
Nov 15, 2022

Conversation

ChristianGruen
Copy link
Contributor

No description provided.

@ChristianGruen
Copy link
Contributor Author

It appears no diffs were generated for my pull request. Maybe I missed something (or I am just too impatient)?

image

@ChristianGruen
Copy link
Contributor Author

ChristianGruen commented Oct 13, 2022

It was my impatience that needs to be blamed. All fine now.

@michaelhkay
Copy link
Contributor

I think it would be useful to try to write a summary that explains to people why they might want to use this function. Something like "Processes a supplied value repeatedly, continuing while some condition remains true, and returning the first value that does not satisfy the condition."

I think this is one of those functions where it would help the reader if the rules were structured as "informally, X. More formally, the function is equivalent to..."

Perhaps the informal explanation (if I have understood it correctly) is something like this.

Informally, the function behaves as follows:

  1. The supplied $input value is tested against the supplied $predicate.
  2. If the result of the predicate is true, a new $input value is evaluated as the result of $action($input), and the process repeats from step 1
  3. If the result of the predicate is false, the function returns the value of $input.

It would be nice to give a simple XML example, for example a function that returns the value of @xml:space on the nearest ancestor-or-self that has such an attribute.

I'm not quite sure what is meant by "a single argument" in the Errors section.

The Notes section might be a good place to put some discussion of why the function has been introduced and when it's useful: the examples give the reader some ideas, but I think more narrative would be useful.

@michaelhkay
Copy link
Contributor

We might also like to consider that having a function named "while" prevents us ever using "while" as a language keyword.

(Perhaps fn:iterate() would suggest that the function is in the same general area as xsl:iterate?)

@michaelhkay
Copy link
Contributor

And another idea for an example/use-case - does it make sense to use the function in conjuction with random-number-generator()?

@michaelhkay
Copy link
Contributor

Now implemented - 10 lines of code, so it must be a pretty clean spec. All tests passing except while-014 which depends on the -> operator, and while-016 which fails with a numeric precision issue. Rounding the result before testing would be useful.

@michaelhkay
Copy link
Contributor

Readers should be made aware that it's very easy to construct an infinite loop using this function if not used correctly.

@ChristianGruen
Copy link
Contributor Author

Thanks for the suggestions from a near(est)-native speaker, very appreciated. I’ll incorporate your suggestions as good as possible.

The structure of my text was mostly inspired by the fold functions. I’m not sure: Maybe we should give them an informal section as well?

I'm not quite sure what is meant by "a single argument" in the Errors section.

Maybe “one argument” sounds better? The error section is basically a mixture from the corresponding sections for fn:fold-left/fn:fold-right (which look at the arguments) and fn:filter/array:filter (which look at the return values). I’m uncertain if the result is really consistent, though, and I noticed that other functions with higher-order function parameters – fn:index-where, fn:for-each, etc. – have no error section at all.

Maybe we should simply skip this section, as we more or less seem to explain here how function arguments are to be evaluated in general?

We might also like to consider that having a function named "while" prevents us ever using "while" as a language keyword.

I wonder if that wouldn’t apply to fn:some as well, when thinking of the some keyword in quantifier expressions? And I assume that we could still use while inside a FLWOR expression, even if we had an equally named function?

(Perhaps fn:iterate() would suggest that the function is in the same general area as xsl:iterate?)

Personally, I would probably be confused (without reading the spec and without knowing about XSLT) why a language has for-each and iterate.

And another idea for an example/use-case - does it make sense to use the function in conjuction with random-number-generator()?

I haven’t used the function a lot. Do you have an example in your mind that I can add?

All tests passing except while-014 which depends on the -> operator

Would you recommend removing -> from the upcoming text cases, or was it just an observation?

and while-016 which fails with a numeric precision issue. Rounding the result before testing would be useful.

I see. I’ll update the test case.

@michaelhkay
Copy link
Contributor

As regards the keyword, It could certainly lead to parsing difficulties, e.g. if we had a function called "where" then we couldn't allow "where" as the first clause in a FLWOR expression (something that would make sense to allow).

In practice it's probably not the technical grammar ambiguity that's the issue, as the user confusion that could result if we use the same word to mean different things in different contexts.

@michaelhkay
Copy link
Contributor

I've been fairly guilty myself in using syntax that isn't yet accepted in test cases, so I can't really complain. But it's probably best avoided if unnecessary - there's a general principle when writing tests to focus on the feature you're testing.

@michaelhkay
Copy link
Contributor

Trying to use random-number-generator to generate a random sequence (or anything else to generate a sequence), I find myself wanting to output values when the predicate is true, rather than accumulating them until it is false. xsl:iterate has the advantage that you can add values to the output at any stage of the iteration, and also that you can pass any number of values (parameters) from one iteration to the next. The xsl:iterate/on-completion clause (like a FLWOR return) also enables the final result to be computed from the running state. With fn:while, this seems to require maintaining a map to maintain state - and that also means the initial value and final result also have to use the same map structure, which exposes the internal state on completion. Perhaps I shouldn't have been thinking of this function as a sequence generator.

michaelhkay added a commit to qt4cg/qt4tests that referenced this pull request Oct 13, 2022
Minor reverts (arrows, named arguments; see qt4cg/qtspecs#210)
@ChristianGruen
Copy link
Contributor Author

As regards the keyword, It could certainly lead to parsing difficulties, e.g. if we had a function called "where" then we couldn't allow "where" as the first clause in a FLWOR expression (something that would make sense to allow).

Wouldn’t we have to rename fn:some as well, then? ExprSingle can be both a FLWORExpr and QuantifiedExpr.

Trying to use random-number-generator to generate a random sequence […]

I’ve concocted a little example which I’ll add in my updated version. I won’t be offended if you plan to edit my pull request (I don’t know if the notes will be explanatory enough).

@michaelhkay
Copy link
Contributor

The clause keywords that are always followed by "$" (for, let, some, every) are less of a problem - the presence of "$" or "(" immediately distinguishes whether its a function call.

@ChristianGruen ChristianGruen mentioned this pull request Oct 16, 2022
@ndw
Copy link
Contributor

ndw commented Oct 19, 2022

Formatted versions of the specifications with this PR applied are available

@cmsmcq
Copy link

cmsmcq commented Oct 25, 2022

Looks good for the most part. I have some editorial notes.

  • In 16.2.7, the sentence beginning "While loops are very common in procedural programming languages, ..." is a classic garden-path sentence. I suggest hyphenation: "While-loops are very common in procedural programming languages, ..."
  • For "Note that, similar to when writing recursive functions, it is easily possible to construct infinite loops." perhaps read "Note that, just as when writing recursive functions, it is easy to construct infinite loops."

@ChristianGruen
Copy link
Contributor Author

@cmsmcq Thanks, very appreciated. I have incorporated your suggestions.

@ChristianGruen
Copy link
Contributor Author

A summary of the comments, for next week’s meeting:

We need to decide if we want to stick with the function name. It would prevent us from using while as a language keyword, e.g. as the first clause in a FLWOR expression (provided that we made let or for optional). while would then be ambiguous in the following example:

while (...test...)
return ...result...

Alternatives could be:

  • fn:until, with the semantics of the predicate function reversed and as initially proposed in [FO] fn:while (before: fn:until) #80.
  • Proposed by Michael Kay in the comments above: fn:iterate, in analogy to xsl:iterate.

@Arithmeticus
Copy link
Contributor

The function seems quite useful. In fact, as I think of using it, my first impulse would be to use it as a keyword, on analogy to if or for. Could there be discussion, while this proposal is open, on exposing the functionality via keyword? (One possibility to hack into while: introduce the expression break to exit a for)

@ChristianGruen
Copy link
Contributor Author

@Arithmeticus Thanks.

I think that both a function and keyword could be beneficial. Michael Kay has added a proposal for a while clause in FLWOR expressions in #187.

@ChristianGruen
Copy link
Contributor Author

I’ve renamed the function from fn:while to fn:iterate-while, as proposed by @dnovatchev in #80 (comment) (thanks).

@ChristianGruen ChristianGruen changed the title fn:while. #80 fn:iterate-while. #80 Nov 14, 2022
@ChristianGruen ChristianGruen changed the title fn:iterate-while. #80 Issue 80: fn:iterate-while (before: fn:while) Nov 14, 2022
@cmsmcq
Copy link

cmsmcq commented Nov 15, 2022

Looks good, I think. For the second rule I wonder if a different formulation would be clearer. For:

If the result of the predicate is true, a new $input value is evaluated as the result of $action($input), and the process repeats from step 1.

perhaps read:

If the result of the predicate is true, the $action function item is called with the $input as its argument (i.e. the expression $action($input) is evaluated), the resulting value is used as a new $input, and the process repeats from step 1.

(This is longer than I hoped when I started, and if we can shorten it that would be good.) The key change for me is to say more clearly that the input value is produced by evaluating the action.

@ChristianGruen
Copy link
Contributor Author

@cmsmcq Thanks. I’ve changed it to:

If the result of the predicate is true, $action($input) is evaluated, the resulting value is used as a new $input, and the process repeats from step 1.

@ndw
Copy link
Contributor

ndw commented Nov 15, 2022

Approved at meeting 011, 15 November 2022

@ndw ndw merged commit 5872cf5 into qt4cg:master Nov 15, 2022
ndw added a commit to ndw/qtspecs-xslt4 that referenced this pull request Nov 16, 2022
Issue 80: fn:iterate-while (before: fn:while)
@ChristianGruen ChristianGruen deleted the fn-while branch April 6, 2023 08:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants