[Bug 29346] New: [XP31] XPath-style currying, or the arrow operator, may require a bit more specification

https://www.w3.org/Bugs/Public/show_bug.cgi?id=29346

            Bug ID: 29346
           Summary: [XP31] XPath-style currying, or the arrow operator,
                    may require a bit more specification
           Product: XPath / XQuery / XSLT
           Version: Candidate Recommendation
          Hardware: PC
                OS: Windows NT
            Status: NEW
          Severity: normal
          Priority: P2
         Component: XPath 3.1
          Assignee: jonathan.robie@gmail.com
          Reporter: abel.braaksma@xs4all.nl
        QA Contact: public-qt-comments@w3.org
  Target Milestone: ---

Today's discussion with Christian GrĂ¼n and Florent Georges (see
https://lists.w3.org/Archives/Public/public-xsl-query/2015Dec/0028.html etc)
led me to writing this bug, it seems that the production rules and their
explanation of the current consensus, plus the text in this part of the spec
are not entirely in line.

This applies to 3.22 Arrow operator (=>) of the internal WD (CR).

The production rules are as follows:

  ArrowExpr ::= UnaryExpr ( "=>" ArrowFunctionSpecifier ArgumentList )*
  ArrowFunctionSpecifier ::= EQName | VarRef | ParenthesizedExpr

The mandatory part of the spec in this section says:

<quote>
[Definition: An arrow operator applies a function to the value of a primary
expression, using the value as the first argument to the function.] If $s is a
sequence and f() is a function, then $s=>f() is equivalent to f($s), and
$s=>f($j) is equivalent to f($s, $j).
</quote>

The (possible) issues:
----------------------

1) The text says "and f() is a function", but f() can never be a function. It
can be a function call, or a function call evaluating to a function.

Suggestion, something like: "if ArrowFunctionSpecifier is either a function, a
variable reference bound to a function or an expression evaluating to a
function"

2) We don't specify what happens if this goes wrong. Maybe we don't need to,
but I wonder what a => (concat#3)("b") would return. The spec suggests this is
equivalent to (concat#3)(a, "b") but this will raise XPTY0004 (wrong no of
args). Should we emphasize this can happen? Or will the returned value be a new
function, with one argument, as in (concat#3)(a, "b", ?)?

3) Bug #26889 has some discussion that suggests placeholder-syntax cannot be
used as the rhs. However, I believe the production rules, and the accompanying
text leave room for a => (concat('b', ?)) being valid. Should it not be? I
think it makes sense it is valid, but if it isn't, we should probably say so.

I believe it is valid because
a) we allow ParenthesizedExpr
b) the rhs translates to a function taking one argument
c) the equivalence-rule applies, turning this effectively in (concat('b',
?))(a), which is still legal.

4) The example in (3) is notably different from a => concat('b', ?), which
translates to concat('a', 'b', ?). Still valid (returning a function item), but
this difference is hard to spot and very subtle. While people have grown used
to using parentheses to remove ambiguity of the comma operator, the difference
between concat('b', ?) and (concat('b', ?)) is almost indiscernible.

If my interpretation is correct, perhaps we could mention this as a Note?

I believe this is valid because:
a) the prod rules above use ArgumentList
b) which allows for Argument between the ","
c) which allows for either an ArgumentPlaceHolder or a SingleExpr

5) We don't mention the possible occurrence of the rhs. Considering the
equivalence rules, it stands to reason that
a) if rhs is empty sequence, an error is raised (cannot have empty seq. as
target of a function call, XPTY0004)
b) if rhs has more-than-one, an error is raised (cannot have more-than-one as
target of a function call, XPTY0004)

Though I wouldn't mind allowing something other than exactly-one, that's
probably too much a change at CR stage (besides other idiosyncrasies this may
raise)

Not sure this point requires a change, other than perhaps pointing out that the
same errors apply as for a (dynamic) function call, whichever applies.

6) The text calls upon the equivalence with normal function calls, but we don't
allow NamedFunctionRef as an alternative in ArrowFunctionSpecifier, though with
"normal" function calls it is allowed. For consistency, it seems appropriate to
allow it (currently, it is allowed, but requires parentheses).

This would make (a, b) => string-join#1() legal. Perhaps not a big win, but at
least consistent and a small change. It is strange that (a, b) =>
(string-join#1)() is a required rewrite to make this expression valid.


PS: I used "currying" in the title not because it is the same as currying in
other functional languages (it is not), but because it does allow to return a
partial applied function as the result of the arrow expression, which is "kind
of" currying (except that, if you chain an operation that way using arrows, you
need parentheses).

-- 
You are receiving this mail because:
You are the QA Contact for the bug.

Received on Friday, 18 December 2015 01:26:34 UTC