-
Notifications
You must be signed in to change notification settings - Fork 15
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
new function - fn:tail-recurse a function to allow users to hand roll their recursion and guarentee tail recursion. #1221
Comments
I'm sorry, I don't understand what you are asking for. Apart from the title, all I see is a lot of code, and I can't reverse engineer your requirement from the code. Are you perhaps looking for something like the new do-until() and while-do() functions? |
Same for me. Would it be possible to add a minimized XPath example that demonstrates what would happen with and without using the proposed function? |
ah ok, hmmm let me rejig it all a bit then, |
its now rejigged and hopefully a bit more understandable. |
If I've understood it correctly the end result is exactly what can be achieved with Something like
Bringing in tail recursion seems just to complicate the discussion. There's no need for recursion here, so no need to detect tail calls. |
I’ll keep watching, my XSLT knowledge is too limited to digest all of this in a few minutes (unless you can express it in XQuery?).
For loops, you can use the for $n in 1 to 10
return $n * $n For recursive functions, you can declare function items and pass a self reference to the invoked function… let $func := function($f) { $f($f) }
return $func($func) …but the XQuery approach is certainly better readable: declare function local:f() {
local:f()
};
local:f() |
I assume do-until() or while-do() actually don't currently exist? in which case yes, loops are tail recursion, there is no difference (I can map code 1:1 and back), you've just changed the label, those labels are probably better. (from a functional perspective though the issue is the inability to define a tail recursion, 'loops' don't exist, an imperative programmer would never ask for this because while loops exists in the foundation) Just to be clear though the motivation is writing a recursive function and not being able to explicitly define it in tail recursive terms, if people want to additionally see it as an imperative construct for 'looping', I have no problem with that, and it solves the problem BUT it isnt my motivation, one could easily tell devolopers to write such a function, and then they find it isnt tail recursive in their runtime and the problem isnt solved. |
I can try tomorrow, my XQuery is limited too.
here you know in advance the termination point, I'm talking about scenarios where you don't know, e.g. a function that given a prime returns the next prime, you need
yes but this is not inherently tail recursive
absolutely, this is recursive, but in general unless the runtime detects tail recursion, this sort of thing can blow the stack.
as suggested by MK is a better name, though implies a more imperative style signature I'll try to write it in XQuery tomorrow |
Even better if you are already aware of the syntax. I just mentioned the examples to help you generate an XPath/XQuery example for
Visit the following links to learn more about |
ah ok, I did check the existing specs, and I thought id checked the 4.0 spec, though maybe I don't know where they all are. ignore me, I think fn:do-until would do it. |
Feel free to close the issue if you think it is resolved. |
Motivation:
So,
Tail recursion is not an uncommon problem in other languages, in imperative languages I would simply implement the algorithm using a 'while' loop, creating the 'body' of the while loop is my problem, but once I've done it, I KNOW that in all implementations my algorithm will be executed tail recursively (imperative code is FULL of loops, stack overloads are not an issue).
An example
I want to implement a power function in C# I know how to write it recursively, but C# doesn't support tail recursion, so I have to turn it into a loop. I could do this in an ad hoc way using a while loop, but I could also write the loop once, and then ask the developer to pass in a function that defines the body of the loop
in C# that function could have the type (i.e. it takes a state and either returns a new state or null, a null would indicte the end of the 'loop')
State? recurse(State state)
and the library function that executes it have the signature:
State TailRecurse<State>(Func<State,State?> f, State state)
a complete example of how this would appear in C# would be:
(note C# has a nuance w.r.t. the higher kinded type '?' and so the signature of TailRecurse below is slightly weaker than the one above).
in XSLT I could write this function
I know its tail recursive, but my environment may not for whatever reason detect it (I would hope it does, but I could be doing something much more complex, that IS tail recursive but the environment simply doesn't see it).
I can't write a loop in XPath etc, it doesnt exist, so I can't escape like I do in C# or scala, in F# (which also doesnt support while loops), I would have to write a function that I was sure F# detected as tail recursive and then path the 'body' of the while loop as a function.
in XSLT this could look like this (basically the same as the C# example)
here the C# signature
State TailRecurse<State>(Func<State,State?> f, State state)
has been translated by using
item()*
for state anarray(*)
for State?, where an empty array corresponds to null/none, and an array with 1 element corresponds to 'some' State.This function IS tail recursive in a very simple way that I think all implementations would detect as such, and thus (if it does) I can pass any function I like and be confident it is processed tail recursively - I can of course do this now, I use saxon, (even though I'm wrestling with it to detect tail recursion for some bizarre reason which is probably my fault) I think it would ideally be a library function and (using a loop) allow non tail recursive environments to support tail recursion, or allow me to simply do the detection myself.
For environments that don't do tail recursion detection, they can simple implement the analogous code to the C# example in their implementation i.e. map it to a while loop.
In both cases I think this is hopefully trivial for the implementor of the language.
Here's a complete example, with tailRecurse defined as above, that would guarentee (in an environment that detected it correctly) that any passed function is processed.
I suspect these lines are not obvious.
The first line says anything to the power 0 is 1, the second line says, I want the 'result of 2 to the power 4.
Note its VERY similar to xsl:iterate, but that requires an sequence to drive it, this is just general recursion.
The text was updated successfully, but these errors were encountered: