This seems limited to anonymous functions. I can do this:

xquery version "3.0";

let $a := function($x as item()*, $f as function) as xs:boolean {
    $f($x)
}

let $b := function($x as item()*) as xs:boolean {
    true()
}

let $list := (
    <test/>
)

let $f := $a(?,$b)

return $f($list)


2013/8/29 W.S. Hager <wshager@gmail.com>
Then there is a bug in eXist: I can't pass functions as arguments to curry. Execution also stops upon encountering the currying with function arg. Simple test:

xquery version "3.0";

declare variable $a := function($x as item()*, $f as function(item()*) as
xs:boolean) as xs:boolean {
    $f($x)
};

let $list := (
    <test/>
)

let $f := $a(?,function($x){ true() })

return $f($list)


2013/8/29 Adam Retter <adam@exist-db.org>
Yes the test I mentioned was done using Saxon as I was away from my
Laptop and did not have a copy of eXist handy. If it works in Saxon it
*should* work in eXist, if not it is most likely a bug - let us
know...

On 29 August 2013 09:56, W.S. Hager <wshager@gmail.com> wrote:
> Hi Adam,
>
> Currying was indeed what I did to get anonymous expressions into square
> brackets. However, neither functions assigned to variables nor currying with
> ? yielded any results. Did you test those?
>
> Thanks.
>
> Wouter
>
>
> 2013/8/28 Adam Retter <adam@exist-db.org>
>>
>> I just realised that for an even more natural syntax, you could in
>> fact use declared variables assigned to anonymous instead of declared
>> functions for the logic, i.e.:
>>
>> declare variable $or := function($ctx as item()*, $left as
>> function(item()*) as xs:boolean*, $right as function(item()*) as
>> xs:boolean*) as xs:boolean {
>>     $left($ctx) = true() or $right($ctx) = true()
>> };
>>
>> declare variable $and := function($ctx as item()*, $left as
>> function(item()*) as xs:boolean*, $right as function(item()*) as
>> xs:boolean*) as xs:boolean {
>>     $left($ctx) = true() and $right($ctx) = true()
>> };
>>
>> declare variable $p := function($ctx as item()*, $fn as
>> function(item()*) as xs:boolean) as xs:boolean {
>>     $fn($ctx) = true()
>> };
>>
>> $list[$p(.,
>>     $and(?,
>>         function($ctx) { $ctx/type = "Paperback" },
>>         $or(?, function($ctx) { $ctx/empty(date) },
>> function($ctx) { $ctx/date > '2013-01-01' })
>>     )
>> )]
>>
>>
>> Cheers Adam.
>>
>> On 28 August 2013 22:21, Adam Retter <adam@exist-db.org> wrote:
>> > I think I am correct in saying that the functional approach that you
>> > want to achieve is possible using currying. A predicate is basically
>> > an expression that evaluates to an `effective boolean value`, as such
>> > you can use any function that returns true() or false(). Such a
>> > function can be built dynamically by using partial function
>> > application (to achieve currying) and function passing.
>> >
>> > I have no idea of the performance profile of this approach, however I
>> > would guess that the optimiser could not yet do anything with this
>> > approach. But if your really careful, you might not need the optimiser
>> > anyway ;-) I would love to hear Wolfgang's thoughts on this...
>> >
>> > I think the downside to the approach below, is that each thing in the
>> > context ($ctx) may need to be checked against your evaluation, whereas
>> > inside a predicate with the optimiser, I guess as soon as the first
>> > true result is found when working with a sequence it can stop
>> > evaluation. This may still hold, I am not so clear on some of the
>> > internals of eXist's optimisation strategy.
>> >
>> > Basically you can dynamically build your predicate like so -
>> >
>> > xquery version "3.0";
>> >
>> > declare function local:and($ctx as item()*, $left as function(item()*)
>> > as xs:boolean*, $right as function(item()*) as xs:boolean*) as
>> > xs:boolean {
>> >     $left($ctx) = true() and $right($ctx) = true()
>> > };
>> >
>> > declare function local:or($ctx as item()*, $left as function(item()*)
>> > as xs:boolean*, $right as function(item()*) as xs:boolean*) as
>> > xs:boolean {
>> >     $left($ctx) = true() or $right($ctx) = true()
>> > };
>> >
>> > declare function local:predicate($ctx as item()*, $fn as
>> > function(item()*) as xs:boolean) as xs:boolean {
>> >     $fn($ctx) = true()
>> > };
>> >
>> > You could then apply your predicate using -
>> >
>> > $list[local:predicate(.,
>> >     local:and(?,
>> >         function($ctx) { $ctx/type = "Paperback" },
>> >         local:or(?, function($ctx) { $ctx/empty(date) },
>> > function($ctx) { $ctx/date > '2013-01-01' })
>> >     )
>> > )]
>> >
>> > The three anonymous inline functions above that are effectively your
>> > equality tests, could easily be generated by further function calls, I
>> > have simply inlined them to keep the example simple.
>> >
>> > For testing this, I used the following -
>> >
>> > let $data := (
>> >     <container>
>> >         <type>Paperback</type>
>> >         <date>2013-01-02</date>
>> >     </container>) return
>> >
>> > local:predicate(
>> >     $data,
>> >     local:and(?,
>> >         function($ctx) { $ctx/type = "Paperback" },
>> >         local:or(?, function($ctx) { $ctx/empty(date) },
>> > function($ctx) { $ctx/date > '2013-01-01' })
>> >     )
>> > )
>> >
>> >
>> > You may also be interested in this -
>> > https://github.com/jpcs/functional.xq
>> > I would think that the curry and compose functions could prove useful to
>> > you.
>> >
>> > ...It's just "Turtles all the way down" ;-)
>> >
>> >
>> >
>> > On 28 August 2013 15:17, W.S. Hager <wshager@gmail.com> wrote:
>> >> Hi,
>> >>
>> >> I've been looking at a way to make node selections based on xpath
>> >> strings.
>> >> In other words, I want to translate arbitrary pieces of xpath into
>> >> higher-order functions.
>> >>
>> >> Please consider the example:
>> >>
>> >> $list[type eq 'Paperback' and (empty(date) or date > '2013-01-01')]
>> >>
>> >> This is pretty straightforward in xpath. However, in my app I want to
>> >> reassemble the xpath expression from query parameters. I currently use
>> >> util:eval to evaluate the stuff between square brackets above.
>> >>
>> >> However, eval is evil and the performance is not good enough for more
>> >> complex expression. So I thought I'd try to compose the expression out
>> >> of
>> >> higher-order functions.
>> >>
>> >> Please consider this xquery 3.0:
>> >>
>> >> declare function local:and($a, $b) {
>> >>     $a and  $b
>> >> };
>> >>
>> >> declare function local:or($a, $b) {
>> >>     $a or  $b
>> >> };
>> >>
>> >> declare function local:eq($p, $t) {
>> >>     $p eq  $t
>> >> };
>> >>
>> >> declare function local:gt($p, $t) {
>> >>     $p gt  $t
>> >> };
>> >>
>> >> declare function local:comp($x as node()*,$p as xs:string,$t as
>> >> xs:string,
>> >> $f as function) {
>> >>         $x/*[name(.) = $p][$f(.,$t)]
>> >> };
>> >>
>> >> declare function local:comp($x as node()*,$p as xs:string,$f as
>> >> function) {
>> >>         $x/*[name(.) = $p][$f(.)]
>> >> };
>> >>
>> >> return collection("/db/titles")//root[local:and(
>> >>     local:comp(.,'type','Paperback',local:eq#2),
>> >>     local:or(
>> >>         local:comp(.,'date',empty#1),
>> >>         local:comp(.,'date','2013-01-01',local:gt#2)
>> >>     ))]
>> >>
>> >>
>> >> However, performance is even worse than util:eval. Is there any way to
>> >> improve upon "util:eval with a concatenated xpath string", or are there
>> >> other viable approaches closer to the one above?
>> >>
>> >> Thanks.
>> >>
>> >> PS. as you can see there's more to improve in the above, because the
>> >> functions are still stated within square brackets to prevent for-loops.
>> >>
>> >> --
>> >>
>> >> W.S. Hager
>> >> Lagua Web Solutions
>> >> http://lagua.nl
>> >>
>> >>
>> >>
>> >> ------------------------------------------------------------------------------
>> >> Learn the latest--Visual Studio 2012, SharePoint 2013, SQL 2012, more!
>> >> Discover the easy way to master current and previous Microsoft
>> >> technologies
>> >> and advance your career. Get an incredible 1,500+ hours of step-by-step
>> >> tutorial videos with LearnDevNow. Subscribe today and save!
>> >>
>> >> http://pubads.g.doubleclick.net/gampad/clk?id=58040911&iu=/4140/ostg.clktrk
>> >> _______________________________________________
>> >> Exist-open mailing list
>> >> Exist-open@lists.sourceforge.net
>> >> https://lists.sourceforge.net/lists/listinfo/exist-open
>> >>
>> >
>> >
>> >
>> > --
>> > Adam Retter
>> >
>> > eXist Developer
>> > { United Kingdom }
>> > adam@exist-db.org
>> > irc://irc.freenode.net/existdb
>>
>>
>>
>> --
>> Adam Retter
>>
>> eXist Developer
>> { United Kingdom }
>> adam@exist-db.org
>> irc://irc.freenode.net/existdb
>
>
>
>
> --
>
> W.S. Hager
> Lagua Web Solutions
> http://lagua.nl



--
Adam Retter

eXist Developer
{ United Kingdom }
adam@exist-db.org
irc://irc.freenode.net/existdb



--

W.S. Hager
Lagua Web Solutions
http://lagua.nl




--

W.S. Hager
Lagua Web Solutions
http://lagua.nl