Thinking about port set expressions and block expressions

It's been a long time since we talked about the signatures for steps.
Suppose we used square brackets there too:

  declare step xslt($mode as xs:QName, $params as map())
        [$source, $stylesheet; $result, $secondary]

  Aside: we seem to have some inconsistency about whether port names
  have $-prefixes or not.

I'm not sure it's syntactically the best thing ever, but ...

Now we can say that a port set expression provides a mapping of
readable ports for the step that follows:

  [source="doc.xml", "style.xsl"] -> xslt()

(I kind of like the arrow for readability but I think Henry's right,
it has no purpose except readability.)

I imagine that the semantics of that mapping are something like this:

Given a set of readable ports and a set of input ports, you match up
the named ones first then you match up the remaining ones in order.

So each of the following binds source and stylesheet for the following
xslt() step just as you'd expect:

  [source="doc.xml", "style.xsl"] -> xslt()
  [source="doc.xml", stylesheet="style.xsl"] -> xslt()
  [stylesheet="style.xsl", source="doc.xml"] -> xslt()
  ["doc.xml", "style.xsl"] -> xslt()

For a case where the named and ordinal ones are "out of order":

  [stylesheet="style.xsl", "doc.xml"] -> xslt()

I think there are two alternatives. We can say that this binding works
by matching up the stylesheet port by name and the source port from
the remaining possibilities ordinally or we can make it an error
because you have to "go backward" to make it work. (I can't think of a
concise way to express the error condition, but I think I can see it
pretty clearly.)

I'm naturally inclined to prefer to make it an error, but I'm not sure
that's the right thing because I don’t think we want to make extra
ports an error. I think both:

  [source="doc.xml", "style.xsl", "alt.xml"] -> xslt()
  [source="doc.xml", alt="alt.xml", stylesheet="style.xsl"] -> xslt()

bind source to "doc.xml" and stylesheet to "style.xsl" in the XSLT
step. The extra binding is just ignored; there's no way for the XSLT
step to read it.

Another interesting case is when the names don't match up at all:

  [result="doc.xml", "style.xsl"]

I think the right answer here is to say that names which don't match
are ignored. So the preceding port set expression is exactly
equivalent to ["doc.xml", "style.xsl"] for a following xslt() step;
if the following step has a 'result' input port then it gets doc.xml.

Absent ports are just treated as empty:

  [stylesheet="style.xsl"] -> xslt()

binds the stylesheet to "style.xsl" and leaves the source input empty.
I suppose you could also do that this way: [(), "style.xsl"] though
I'm not sure we've worked out what kinds of expressions can go in a
port set expression.

The result of a step is, I think, a port set expression that binds
the output ports to the results. So the xslt() step produces a binding
that's equivalent to this:

   [result="result.xml", secondary="secondary.xml"]

By the rule that says that port names that don't match are simply
ignored, we can still say that:

   xslt() -> store(href="output.xml")

would store "result.xml" into "output.xml" but would do nothing with
the secondary output. If you want to remap things, you have to put in
a port set expression.

   xslt() -> [source=port("secondary")] -> store("secondary.xml")

And it occurs to me that a port set expression doesn't even need
the port() function if we say that it can refer to the names of
readable ports directly:

   xslt() -> [$secondary] -> store("secondary.xml")

All of the preceding is back-formation from my idea for block
expressions, which is to make them anonymous steps.

xproc version = "2.0";
inputs  $source as document-node();
outputs $result as document-node();

[$source] → λ()[$in;$out] { if (xs:decimal($in/*/@version) < 2.0)
                            then [$in,"v1schema.xsd"] → validate-with-xml-schema() ≫ $out
                            else [$in,"v2schema.xsd"] → validate-with-xml-schema() ≫ $out }
          → [$out,"stylesheet.xsl"] → xslt()
≫ $result

It's a little bit of extra syntax, but I think JavaScript and futures
have made anonymous functions commonplace.

They also afford some interesting flexibility, consider:

xproc version = "2.0";
inputs  $source as document-node();
outputs $result as document-node();
options $minver as xs:decimal := 2.0,
        $v1schema := "v1schema.xsd",
        $v2schema := "v2schema.xsd";

[$source] → λ($vertest as xs:decimal := $minver,
              $v1 as xs:string := $v1schema,
              $v2 as xs:string := $v2schema)
            { if (xs:decimal($in/*/@version) < $vertest)
                            then [$in,$v1] → validate-with-xml-schema() ≫ $out
                            else [$in,$v2] → validate-with-xml-schema() ≫ $out }
          → [$out,"stylesheet.xsl"] → xslt()
≫ $result

I'm not sure how useful that is, really, but ...

                                        Be seeing you,

Norman Walsh
Lead Engineer
MarkLogic Corporation
Phone: +1 512 761 6676

Received on Friday, 15 April 2016 15:29:28 UTC