Hello --
So I'm trying to do this:
import module namespace xcs = "http://www.xcential.com/xquery/utils/script" at "same-words-same-order-script.xqm"; (: we don't need xc computationally but there are external variables in that namespace in scope :) import module namespace xc = "http://www.xcential.com/xquery/utils" at 'same-words-same-order.xqm';
declare function xc:dropTableLines($in as node()*,$toggle as xs:boolean) as node()* { switch (true()) case empty($in) return () case starts-with(head($in),':stab') return (<line/>,xc:dropTableLines(tail($in),true())) case starts-with(head($in),':rtab') return (<line/>,xc:dropTableLines(tail($in),false())) case $toggle return (<line/>,xc:dropTableLines(tail($in),$toggle)) default return (head($in),xc:dropTableLines(tail($in),$toggle)) };
let $test as element() := <text> <line></line> <line></line> <line>:stab</line> <line>weasels</line> <line>:stab</line> <line>weasels</line> <line></line> <line></line> <line>:rtab.</line> <line></line> <line>asparagus</line> <line></line> <line></line> <line>:stab</line> <line></line> <line>weasels</line> <line>:rtab.</line> <line>asparagus</line> <line>asparagus</line> <line>asparagus</line> <line>asparagus</line> <line>asparagus</line> <line>:stab</line> <line>:stab</line> <line></line> <line></line> <line>:stab</line> <line></line> <line>weasels</line> <line></line> <line>:rtab.</line> <line></line> <line>asparagus</line> <line></line> <line></line> <line></line> </text>
return element {'text'} { xc:dropTableLines($test/line,false()) }
Only at scale the stack blows up and I get the "try tail recursion?" suggestion. I would have tried hof:until for that, since I have to pass the current state of "are we dropping or not dropping intervening content?", but it looks like it's been removed? And the available hof functions in 4 look like they're strictly positional which is actively unhelpful in this case. (At least with whatever brain cells I currently have.)
What's the appropriate pattern for "process a sequence, toggling an action on or off based on the last member of the sequence we looked at?"
Thanks! Graydon
On Wed, 2024-03-27 at 23:57 -0400, Graydon Saunders wrote:
What's the appropriate pattern for "process a sequence, toggling an action on or off based on the last member of the sequence we looked at?"
One approach might be to use fold-left on (1 to count($input)), with $input in scope, so that you can write in the function argument to fold-left things like
if (. eq 1) then $input[.] else if (starts-with($input[. - 1], 'stab') then...
etc
liam
On Thu, Mar 28, 2024 at 12:14:45AM -0400, Liam R. E. Quin scripsit:
On Wed, 2024-03-27 at 23:57 -0400, Graydon Saunders wrote:
What's the appropriate pattern for "process a sequence, toggling an action on or off based on the last member of the sequence we looked at?"
One approach might be to use fold-left on (1 to count($input)), with $input in scope, so that you can write in the function argument to fold-left things like
if (. eq 1) then $input[.] else if (starts-with($input[. - 1], 'stab') then...
etc
Yeah, I phrased that badly.
The cases are "I've seen A", "I've seen B (so forget I've seen A)", and "I haven't seen A". There can be multiple instances of A and B and most things are C and what happens to C depends on whether or not we've seen A some time previously in the sequence.
So the approach I want to take is to have a toggle that lets me set "Have seen A" as a boolean and pass it to the subsequent evaluations. This used to be something I could do with hof:until by passing a map as the parameter, but that's not looking like what the current hof functions support.
(I'm using hof:until in other places in this particular task so I'm worried that I'm going to have to replace that code when 11 comes out, too.)
Thanks! Graydon
This feels like an ideal use case for XSLT for-each-group—something that is challenging to implement in XQuery.
Cheers,
E.
_____________________________________________ Eliot Kimber Sr Staff Content Engineer Digital Content & Design O: 512 554 9368 M: 512 554 9368 servicenow.comhttps://www.servicenow.com LinkedInhttps://www.linkedin.com/company/servicenow | Twitterhttps://twitter.com/servicenow | YouTubehttps://www.youtube.com/user/servicenowinc | Facebookhttps://www.facebook.com/servicenow
From: BaseX-Talk basex-talk-bounces@mailman.uni-konstanz.de on behalf of Graydon Saunders graydonish@gmail.com Date: Thursday, March 28, 2024 at 7:43 AM To: BaseX BaseX-Talk@mailman.uni-konstanz.de Subject: [basex-talk] hof:until is gone? [External Email]
________________________________ Hello --
So I'm trying to do this:
import module namespace xcs = "http://www.xcential.com/xquery/utils/scripthttp://www.xcential.com/xquery/utils/script" at "same-words-same-order-script.xqm"; (: we don't need xc computationally but there are external variables in that namespace in scope :) import module namespace xc = "http://www.xcential.com/xquery/utilshttp://www.xcential.com/xquery/utils" at 'same-words-same-order.xqm';
declare function xc:dropTableLines($in as node()*,$toggle as xs:boolean) as node()* { switch (true()) case empty($in) return () case starts-with(head($in),':stab') return (<line/>,xc:dropTableLines(tail($in),true())) case starts-with(head($in),':rtab') return (<line/>,xc:dropTableLines(tail($in),false())) case $toggle return (<line/>,xc:dropTableLines(tail($in),$toggle)) default return (head($in),xc:dropTableLines(tail($in),$toggle)) };
let $test as element() := <text> <line></line> <line></line> <line>:stab</line> <line>weasels</line> <line>:stab</line> <line>weasels</line> <line></line> <line></line> <line>:rtab.</line> <line></line> <line>asparagus</line> <line></line> <line></line> <line>:stab</line> <line></line> <line>weasels</line> <line>:rtab.</line> <line>asparagus</line> <line>asparagus</line> <line>asparagus</line> <line>asparagus</line> <line>asparagus</line> <line>:stab</line> <line>:stab</line> <line></line> <line></line> <line>:stab</line> <line></line> <line>weasels</line> <line></line> <line>:rtab.</line> <line></line> <line>asparagus</line> <line></line> <line></line> <line></line> </text>
return element {'text'} { xc:dropTableLines($test/line,false()) }
Only at scale the stack blows up and I get the "try tail recursion?" suggestion. I would have tried hof:until for that, since I have to pass the current state of "are we dropping or not dropping intervening content?", but it looks like it's been removed? And the available hof functions in 4 look like they're strictly positional which is actively unhelpful in this case. (At least with whatever brain cells I currently have.)
What's the appropriate pattern for "process a sequence, toggling an action on or off based on the last member of the sequence we looked at?"
Thanks! Graydon
hof:until is not gone, it is just hiding [1]
- In 10.7 it is there but undocumented in Wiki - In BaseX 11 you need to use XQuery 4 fn:while-do⁺, fn:do-until⁺ [2]
Hope this helps /Andy
[1] https://www.mail-archive.com/basex-talk%40mailman.uni-konstanz.de/msg15596.h... [2] https://help.basex.org/main/Higher-Order_Functions_Module
On Thu, 28 Mar 2024 at 12:44, Eliot Kimber eliot.kimber@servicenow.com wrote:
This feels like an ideal use case for XSLT for-each-group—something that is challenging to implement in XQuery.
Cheers,
E.
*Eliot Kimber*
Sr Staff Content Engineer
Digital Content & Design
O: 512 554 9368
M: 512 554 9368
servicenow.com https://www.servicenow.com
LinkedIn https://www.linkedin.com/company/servicenow | Twitter https://twitter.com/servicenow | YouTube https://www.youtube.com/user/servicenowinc | Facebook https://www.facebook.com/servicenow
*From: *BaseX-Talk basex-talk-bounces@mailman.uni-konstanz.de on behalf of Graydon Saunders graydonish@gmail.com *Date: *Thursday, March 28, 2024 at 7:43 AM *To: *BaseX BaseX-Talk@mailman.uni-konstanz.de *Subject: *[basex-talk] hof:until is gone? *[External Email]*
Hello --
So I'm trying to do this:
import module namespace xcs = "http://www.xcential.com/xquery/utils/script" at "same-words-same-order-script.xqm"; (: we don't need xc computationally but there are external variables in that namespace in scope :) import module namespace xc = "http://www.xcential.com/xquery/utils" at 'same-words-same-order.xqm';
declare function xc:dropTableLines($in as node()*,$toggle as xs:boolean) as node()* { switch (true()) case empty($in) return () case starts-with(head($in),':stab') return (<line/>,xc:dropTableLines(tail($in),true())) case starts-with(head($in),':rtab') return (<line/>,xc:dropTableLines(tail($in),false())) case $toggle return (<line/>,xc:dropTableLines(tail($in),$toggle)) default return (head($in),xc:dropTableLines(tail($in),$toggle)) };
let $test as element() := <text> <line></line> <line></line> <line>:stab</line> <line>weasels</line> <line>:stab</line> <line>weasels</line> <line></line> <line></line> <line>:rtab.</line> <line></line> <line>asparagus</line> <line></line> <line></line> <line>:stab</line> <line></line> <line>weasels</line> <line>:rtab.</line> <line>asparagus</line> <line>asparagus</line> <line>asparagus</line> <line>asparagus</line> <line>asparagus</line> <line>:stab</line> <line>:stab</line> <line></line> <line></line> <line>:stab</line> <line></line> <line>weasels</line> <line></line> <line>:rtab.</line> <line></line> <line>asparagus</line> <line></line> <line></line> <line></line>
</text>
return element {'text'} { xc:dropTableLines($test/line,false()) }
Only at scale the stack blows up and I get the "try tail recursion?" suggestion. I would have tried hof:until for that, since I have to pass the current state of "are we dropping or not dropping intervening content?", but it looks like it's been removed? And the available hof functions in 4 look like they're strictly positional which is actively unhelpful in this case. (At least with whatever brain cells I currently have.)
What's the appropriate pattern for "process a sequence, toggling an action on or off based on the last member of the sequence we looked at?"
Thanks!
Graydon
Hi Andy --
On Thu, Mar 28, 2024 at 01:06:10PM +0000, Andy Bunce scripsit:
hof:until is not gone, it is just hiding [1]
- In 10.7 it is there but undocumented in Wiki
Which is useful to know -- thank you! -- but makes me think a bunch of my production code is going to break hard when 11 is released. I would really like to avoid that. (In particular, the conversation with management about how much refactoring work will be required.)
- In BaseX 11 you need to use XQuery 4 fn:while-do⁺, fn:do-until⁺ [2]
It is very probably my brain, but I'm having trouble transposing hof:until to those functions. I can an implement what I want to do with hof:until like so:
declare function xc:dropTableLinesFancy($in as node()*) as node()* { let $result as map(*) := hof:until( (: are we done? (= we've run off the end of our list of nodes ) :) function($m) { empty($m?oldNodes) }, (: create new list of line elements :) function($m) { map { 'oldNodes': tail($m?oldNodes), 'newNodes': ($m?newNodes, switch (true()) case starts-with(head($m?oldNodes),':stab') return <line/> case starts-with(head($m?oldNodes),':rtab') return <line/> case $m?toggle return <line/> default return head($m?oldNodes) ), 'toggle': ( switch (true()) case starts-with(head($m?oldNodes),':stab') return true() case starts-with(head($m?oldNodes),':rtab') return false() default return $m?toggle ) } }, (: initial input = we start with no new nodes :) map { 'oldNodes': $in, 'newNodes': (), 'toggle': false() } ) return $result?newNodes };
Anyone willing to provide an example of what that would look like in fn:while-do or fn:do-until?
Thanks! Graydon
Hi Graydon,
Folks tell us it’s time to stop delaying BaseX 11… We’re trying hard.
The good news: The only difference between hof:until [1] and fn:do-until [2] is the order of parameters. The following queries will do the same thing:
hof:until(function($a) { $a > 16 }, function($a) { $a * 2 }, 1) do-until(1, function($a) { $a * 2 }, function($a) { $a > 16 })
With fn:do-until, the input has moved to the first position, the action comes second and the predicate comes last.
Hope this helps, Christian
[1] https://files.basex.org/releases/10.0/BaseX100.pdf [2] https://qt4cg.org/specifications/xpath-functions-40/Overview.html#func-do-un...
On Thu, Mar 28, 2024 at 5:41 PM Graydon graydonish@gmail.com wrote:
Hi Andy --
On Thu, Mar 28, 2024 at 01:06:10PM +0000, Andy Bunce scripsit:
hof:until is not gone, it is just hiding [1]
- In 10.7 it is there but undocumented in Wiki
Which is useful to know -- thank you! -- but makes me think a bunch of my production code is going to break hard when 11 is released. I would really like to avoid that. (In particular, the conversation with management about how much refactoring work will be required.)
- In BaseX 11 you need to use XQuery 4 fn:while-do⁺, fn:do-until⁺ [2]
It is very probably my brain, but I'm having trouble transposing hof:until to those functions. I can an implement what I want to do with hof:until like so:
declare function xc:dropTableLinesFancy($in as node()*) as node()* { let $result as map(*) := hof:until( (: are we done? (= we've run off the end of our list of nodes ) :) function($m) { empty($m?oldNodes) }, (: create new list of line elements :) function($m) { map { 'oldNodes': tail($m?oldNodes), 'newNodes': ($m?newNodes, switch (true()) case starts-with(head($m?oldNodes),':stab') return <line/> case starts-with(head($m?oldNodes),':rtab') return <line/> case $m?toggle return <line/> default return head($m?oldNodes) ), 'toggle': ( switch (true()) case starts-with(head($m?oldNodes),':stab') return true() case starts-with(head($m?oldNodes),':rtab') return false() default return $m?toggle ) } }, (: initial input = we start with no new nodes :) map { 'oldNodes': $in, 'newNodes': (), 'toggle': false() } ) return $result?newNodes };
Anyone willing to provide an example of what that would look like in fn:while-do or fn:do-until?
Thanks! Graydon
-- Graydon Saunders | graydonish@fastmail.com Þæs oferéode, ðisses swá mæg. -- Deor ("That passed, so may this.")
Hi Christian,
That hof:until update recipe is very helpful.
From my occasional reads of qt4 feeds, I guess Graydon's function might
look something like the below I like the look of the upcoming V4.0 features.
/Andy
declare function local:dropTableLinesFancy($in as node()*) as node()* { do-until( (: initial input = we start with no new nodes :) map { 'oldNodes': $in, 'newNodes': (), 'toggle': false() }, fn($m){ map { 'oldNodes': tail($m?oldNodes), 'newNodes': ($m?newNodes, switch { case starts-with(head($m?oldNodes),':stab') return <line/> case starts-with(head($m?oldNodes),':rtab') return <line/> case $m?toggle return <line/> default return head($m?oldNodes) }), 'toggle': switch { case starts-with(head($m?oldNodes),':stab') return true() case starts-with(head($m?oldNodes),':rtab') return false() default return $m?toggle } } }, (: are we done? (= we've run off the end of our list of nodes ) :) fn($m){ empty($m?oldNodes) } )?newNodes };
On Thu, 28 Mar 2024 at 18:34, Christian Grün christian.gruen@gmail.com wrote:
Hi Graydon,
Folks tell us it’s time to stop delaying BaseX 11… We’re trying hard.
The good news: The only difference between hof:until [1] and fn:do-until [2] is the order of parameters. The following queries will do the same thing:
hof:until(function($a) { $a > 16 }, function($a) { $a * 2 }, 1) do-until(1, function($a) { $a * 2 }, function($a) { $a > 16 })
With fn:do-until, the input has moved to the first position, the action comes second and the predicate comes last.
Hope this helps, Christian
[1] https://files.basex.org/releases/10.0/BaseX100.pdf [2] https://qt4cg.org/specifications/xpath-functions-40/Overview.html#func-do-un...
On Thu, Mar 28, 2024 at 5:41 PM Graydon graydonish@gmail.com wrote:
Hi Andy --
On Thu, Mar 28, 2024 at 01:06:10PM +0000, Andy Bunce scripsit:
hof:until is not gone, it is just hiding [1]
- In 10.7 it is there but undocumented in Wiki
Which is useful to know -- thank you! -- but makes me think a bunch of my production code is going to break hard when 11 is released. I would really like to avoid that. (In particular, the conversation with management about how much refactoring work will be required.)
- In BaseX 11 you need to use XQuery 4 fn:while-do⁺, fn:do-until⁺ [2]
It is very probably my brain, but I'm having trouble transposing hof:until to those functions. I can an implement what I want to do with hof:until like so:
declare function xc:dropTableLinesFancy($in as node()*) as node()* { let $result as map(*) := hof:until( (: are we done? (= we've run off the end of our list of nodes ) :) function($m) { empty($m?oldNodes) }, (: create new list of line elements :) function($m) { map { 'oldNodes': tail($m?oldNodes), 'newNodes': ($m?newNodes, switch (true()) case starts-with(head($m?oldNodes),':stab') return <line/> case starts-with(head($m?oldNodes),':rtab') return <line/> case $m?toggle return <line/> default return head($m?oldNodes) ), 'toggle': ( switch (true()) case starts-with(head($m?oldNodes),':stab') return true() case starts-with(head($m?oldNodes),':rtab') return false() default return $m?toggle ) } }, (: initial input = we start with no new nodes :) map { 'oldNodes': $in, 'newNodes': (), 'toggle': false() } ) return $result?newNodes };
Anyone willing to provide an example of what that would look like in fn:while-do or fn:do-until?
Thanks! Graydon
-- Graydon Saunders | graydonish@fastmail.com Þæs oferéode, ðisses swá mæg. -- Deor ("That passed, so may this.")
On Thu, Mar 28, 2024 at 07:33:51PM +0100, Christian Grün scripsit:
Hi Graydon,
Hi Christian,
Folks tell us it’s time to stop delaying BaseX 11… We’re trying hard.
I am generally in favour of 11, or I suppose 4, depending.
The good news: The only difference between hof:until [1] and fn:do-until [2] is the order of parameters. The following queries will do the same thing:
hof:until(function($a) { $a > 16 }, function($a) { $a * 2 }, 1) do-until(1, function($a) { $a * 2 }, function($a) { $a > 16 })
With fn:do-until, the input has moved to the first position, the action comes second and the predicate comes last.
Thank you!
That is helpful indeed. (Definitely my brain.)
And I can confirm it works for me with the current 11 beta.
-- Graydon
basex-talk@mailman.uni-konstanz.de