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