Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

# Hyper operator corner case?

2 views

### David Christensen

Apr 12, 2005, 11:58:40 PM4/12/05
to perl6-l...@perl.org
Hey folks,

I wanted to delurk and address an issue that may need clarification in
regards to hyper operators.

Quoting S03:

> If one argument is insufficiently dimensioned, Perl "upgrades" it:
> (3,8,2,9,3,8) >>-<< 1; # (2,7,1,8,2,7)

Now in this example case, it's pretty clear that the scalar 1 gets
turned into a list of 1s with the length of the lhs. What about the
case of a larger-dimensioned or single-dimensioned array?

Example:
(1,2,3,4,5) >>+<< (1,2)

Is this equivalent to:

a) (1,2,3,4,5) >>+<< (1,2,undef,undef,undef) (undef padding)
b) (1,2,3,4,5) >>+<< (1,2,1,2,1) (repetition)
c) (1,2,3,4,5) >>+<< (1,2,2,2,2) (stretching)
d) (1,2) >>+<< (1,2) (truncation)
e) something else, ie, warnings about mismatched dimension, die(),

Additionally, I was wondering if there was a difference between:

(3,8,2,9,3,8) >>-<< 1

and

(3,8,2,9,3,8) >>-<< (1)

I suppose the answer to that depends on the answer to the above
question.

If the answer is the a) case as above and undef resolves to 0
numerically, then we run into another issue to consider. In the case
of addition and subtraction, 0 is the identity element, and so:

(1,2,3,4,5) >>+<< (1,2) yields (2,4,3,4,5).

But the intuitiveness goes away with multiplication, and completely
blows up with division:

(1,2,3,4,5) >>*<< (1,2) yields (1,4,0,0,0), probably not what we wanted.
(1,2,3,4,5) >>/<< (1,2) yields (1,1,NaN,NaN,NaN), and probably die()s
with division by zero errors.

If in the addition and subtraction cases we want to preserve the
identity cases for the slots not accounted for, undef is fine because
it resolves to 0; to provide the same features for multiplication and
division, the identity element would have to be 1. But that would
suppose that the potential hyper-operators would know what their
appropriate identity elements were (and that such a thing is meaningful
to them).

Additionally, if there is a difference between the automatic scalar
promotion and list promotion, we could run into errors where people
would expect an expression to be a scalar which would be promoted in
the documented fashion, but would really be promoted in one of a)-e),
breaking what they expected:

(1..5) >>+<< (\$a-\$b) # list context for the expression? Promotes like
what?
(1..5) >>+<< +(\$a-\$b) # forced scalar context -- promotes like
documented.
(1..5) >>+<< (1) # promotes like what?

Thoughts?

David Christensen

### Brent 'Dax' Royal-Gordon

Apr 13, 2005, 3:06:54 AM4/13/05
to David Christensen, perl6-l...@perl.org
David Christensen <d...@dwci.net> wrote:
> Example:
> (1,2,3,4,5) >>+<< (1,2)
>
> Is this equivalent to:
>
> a) (1,2,3,4,5) >>+<< (1,2,undef,undef,undef) (undef padding)
> b) (1,2,3,4,5) >>+<< (1,2,1,2,1) (repetition)
> c) (1,2,3,4,5) >>+<< (1,2,2,2,2) (stretching)
> d) (1,2) >>+<< (1,2) (truncation)
> e) something else, ie, warnings about mismatched dimension, die(),

IIRC, it's f) (1,2,3,4,5) >>+<< (1,2,\$identity,\$identity,\$identity),
where \$identity's value is determined by a table something like this:

infix:<+> 0
infix:<-> 0
infix:<~> ''
infix:<*> 1
infix:</> 1
infix:<%> mumble
infix:<x> 1

I could be wrong, though; I can't find any support for it in the design docs.

--
Brent 'Dax' Royal-Gordon <br...@brentdax.com>
Perl and Parrot hacker

"I used to have a life, but I liked mail-reading so much better."

### Thomas Sandlaß

Apr 13, 2005, 11:38:16 AM4/13/05
to perl6-l...@perl.org
Brent 'Dax' Royal-Gordon wrote:
> IIRC, it's f) (1,2,3,4,5) >>+<< (1,2,\$identity,\$identity,\$identity),
> where \$identity's value is determined by a table something like this:

In the case of &infix_circumfix_meta_operator:{'»','«'}:(List,List:&op)
there's no "upgrade"---to use the S03 term. A simple "apply &op where
the lists overlap and keep the rest of the longer one" suffices.
That is (1,2,3,4,5) >>+<< (1,2) becomes (1+1, 2+2, 3, 4, 5). For
works by applying the operator with the scalar to all entries:
(1,2,3,4,5) >>+<< 1 becomes (1+1, 2+1, 3+1, 4+1, 5+1).

What I ask myself is wether (1,2,3) »+ 1 should be a syntax error or just
a different form to express the :(List,Scalar:&) case. BTW, I know that
&infix_prefix_meta_operator:{'»'} isn't mentioned in A12.

> I could be wrong, though; I can't find any support for it in the design docs.

Indeed, "upgrade" is a bit fuzzy ;)
--
TSa (Thomas Sandlaß)

### Larry Wall

Apr 14, 2005, 1:38:04 PM4/14/05
to perl6-l...@perl.org
On Thu, Apr 14, 2005 at 11:08:21AM -0600, John Williams wrote:
: Good point. Another one is: how does the meta_operator determine the
: "identity value" for user-defined operators?
:
: (1,2,3,4,5) >>my_infix_op<< (3,2,4)
:
: Maybe we should say that the excess length is simply copied unchanged.
: But some might argue that not calling the op for each element would be
: cheating somehow. That's not my position, but I cannot think how to
: refute it right now, if you want the side-effects.

One naive possibility is to supply one identity value per precedence level.
Then you could get 0 for addition and 1 for multiplication. Doesn't
really work though, given there are so many different kinds of addition
and multiplication lumped together. Arguably the identity value for %
is Inf.

Another approach to get the side effects would be to assume that
whatever "meta" code is actually calling the scalar operator is
smart enough to coerce ordinary undefs into "undef but identity"
or some such that each individual operator would know how to deal
with rather than generating an exception/undef.

: > What I ask myself is wether (1,2,3) »+ 1 should be a syntax error or just

: > a different form to express the :(List,Scalar:&) case. BTW, I know that
: > &infix_prefix_meta_operator:{'»'} isn't mentioned in A12.
: >
: > > I could be wrong, though; I can't find any support for it in the design docs.

We decided that binary ops should always just have »« on both sides,
since it's essentially just a single "dwim this" bit of information.

Basically, »« is just a flagrant value of "1".

: "Replicate dimensions" is specified in the first version of A3.
:
: The length issue was resolved on the mailing lists.
: Could someone add the ruling to S3 to answer this FAQ?
:
: I believe the fine points fall out like this:
:
: @a >>+<< 1 # replicate
: @a >>+<< (1) # replicate: (1) is still scalar
: @a >>+<< [1] # extend: [1] is an array (and will auto-deref)

Yes. Parens in scalar context do not automagically produce a list.
Comma is another matter, so

@a >>+<< (1,)

turns out to be the same as

@a >>+<< [1]

since there is no scalar comma operator in Perl 6.

All that being said, it's almost certainly the case that (1) is
a mistake. and should perhaps produce a warning: "Useless use of
parentheses" or some such. Not that we frown on useless use of
parentheses in general, since they're often clarifying precedence.
But nobody should be confused about the precedence of a simple term.

Larry

### John Williams

Apr 14, 2005, 1:08:21 PM4/14/05
to Thomas Sandlaß, perl6-l...@perl.org
I found where Damain explains the rule as basically "replicate dimensions,
extend lengths", using an "identity value" when extending the length.
<http://www.mail-archive.com/perl6-l...@perl.org/msg08304.html>

On Wed, 13 Apr 2005, Thomas Sandlaß wrote:

> Brent 'Dax' Royal-Gordon wrote:
> > IIRC, it's f) (1,2,3,4,5) >>+<< (1,2,\$identity,\$identity,\$identity),
> > where \$identity's value is determined by a table something like this:
>
> In the case of &infix_circumfix_meta_operator:{'»','«'}:(List,List:&op)
> there's no "upgrade"---to use the S03 term. A simple "apply &op where
> the lists overlap and keep the rest of the longer one" suffices.
> That is (1,2,3,4,5) >>+<< (1,2) becomes (1+1, 2+2, 3, 4, 5). For
> works by applying the operator with the scalar to all entries:
> (1,2,3,4,5) >>+<< 1 becomes (1+1, 2+1, 3+1, 4+1, 5+1).

Good point. Another one is: how does the meta_operator determine the

"identity value" for user-defined operators?

(1,2,3,4,5) >>my_infix_op<< (3,2,4)

Maybe we should say that the excess length is simply copied unchanged.
But some might argue that not calling the op for each element would be
cheating somehow. That's not my position, but I cannot think how to
refute it right now, if you want the side-effects.

> What I ask myself is wether (1,2,3) »+ 1 should be a syntax error or just

> a different form to express the :(List,Scalar:&) case. BTW, I know that
> &infix_prefix_meta_operator:{'»'} isn't mentioned in A12.
>
> > I could be wrong, though; I can't find any support for it in the design docs.

"Replicate dimensions" is specified in the first version of A3.

The length issue was resolved on the mailing lists.

I believe the fine points fall out like this:

@a >>+<< 1 # replicate
@a >>+<< (1) # replicate: (1) is still scalar
@a >>+<< [1] # extend: [1] is an array (and will auto-deref)

~ John Williams

### Thomas Sandlaß

Apr 15, 2005, 5:10:33 AM4/15/05
to perl6-l...@perl.org
John Williams wrote:
> Good point. Another one is: how does the meta_operator determine the
> "identity value" for user-defined operators?

Does it have to? The definition of the identity value---BTW, I like
the term "neutral value" better because identity also is a relation
between two values---is that \$x my_infix_op \$neutral == \$x.

So the generic implementation that copies surplus elements is correct
with respect to the resulting value. You shouldn't expect the operator
beeing called as many times as there are elements in the bigger data
structure, though. It's called only for positions where both structures
have actual values. But that is the same as short-circuiting && and ||.
And somewhat the reverse of authreading from junctive values.

> I believe the fine points fall out like this:
>
> @a >>+<< 1 # replicate
> @a >>+<< (1) # replicate: (1) is still scalar
> @a >>+<< [1] # extend: [1] is an array (and will auto-deref)

I think they fall out naturally from typing and dispatch. But note
that the » « operator has three args. I haven't made the &op a dispatch
selector. If the my_infix_op from above needs to handle neutral elements
by itself just tell the dispatcher by defining
&infix_circumfix_meta_operator:{'»','«'}:(List,List,&my_infix_op:) and
construct the neutral elements when one of the list runs out of elements.

I hope the syntax I used does what I want to express. Note that in
:(List,List,&my_infix_op:) the first two elements are types while
&my_infix_op is a sub value. In that sense my &op was actually wrong
but it was nice for wording my sentence. So the generic name should read
&infix_circumfix_meta_operator:{'»','«'}:(List,List:Code) or perhaps
&infix_circumfix_meta_operator:{'»','«'}:(List,List:&) if & is considered
as the code sigil. Hmm, then we could also have :(@,@:&) meaning the
same type spec?

BTW, starting from these type specs I come (back) to the suggestion of using
» « for hypering function calls and/or their arguments. Has that been decided?

I'm not sure if specialisation on values is covered by the :() syntax.
E.g. one could implement &infix:<*>:(0,Any) to return 0 without evaluating
the Any term at all! But this needs either lazy evaluation in the functional
paradigma or code morphing 'x() * y()' to '((\$t = x()) != 0) ?? \$t * y() :: 0'
or some such. On assembler level this morphing reduces to an additional
check of a register for zero. But I'm not sure if the type system and the
optimizer will be *that* strong in the near future ;)

Regards
--
TSa (Thomas Sandlaß)

### Roger Hale

Apr 16, 2005, 9:15:50 PM4/16/05
to perl6-l...@perl.org
Thomas Sandlaß wrote:
> John Williams wrote:
>
>> Good point. Another one is: how does the meta_operator determine the
>> "identity value" for user-defined operators?
>
>
> Does it have to? The definition of the identity value---BTW, I like
> the term "neutral value" better because identity also is a relation
> between two values---is that \$x my_infix_op \$neutral == \$x.

One set of cases that doesn't seem to have come up in discussion:

(1, 3, 2) >>-<< (83, 84, 81, 80, 85)

Should this give

(-82, -81, -79, -80, -85)

as it would by hallucinating 0 (neither a left-identity nor left-neutral
element for subtraction strictly, but at least a natural left pivot
element), or

(-82, -81, -79, 80, 85)

as by hallucinating \$neutral - \$x == \$x? This latter \$neutral in fact
doesn't exist among ordinary numbers, and I would call it algebraically
unnatural: for all (other) \$n,

\$n - (\$a + \$b) == (\$n - \$a) - \$b

or, as you increase \$a by \$b, \$n - \$a decreases by \$b (a sort of
contravariance), but

\$neutral - (\$a + \$b) == \$a + \$b == (\$neutral - \$a) + \$b

! This violates algebraic relations I would prefer to rely on, both in
my own reasoning and that of the compiler and other program-handling
programs.

Best regards
Roger

### Thomas Sandlaß

Apr 18, 2005, 10:11:38 AM4/18/05
to perl6-l...@perl.org
Roger Hale wrote:
> One set of cases that doesn't seem to have come up in discussion:
>
> (1, 3, 2) >>-<< (83, 84, 81, 80, 85)
>
> Should this give
>
> (-82, -81, -79, -80, -85)

From an arithmetic point of view it should be exactly that. The
implementation might need to morph the code though, see below.

> as by hallucinating \$neutral - \$x == \$x? This latter \$neutral in fact
> doesn't exist among ordinary numbers, and I would call it algebraically
> unnatural: for all (other) \$n,
>
> \$n - (\$a + \$b) == (\$n - \$a) - \$b
>
> or, as you increase \$a by \$b, \$n - \$a decreases by \$b (a sort of
> contravariance), but
>
> \$neutral - (\$a + \$b) == \$a + \$b == (\$neutral - \$a) + \$b
>
> ! This violates algebraic relations I would prefer to rely on, both in
> my own reasoning and that of the compiler and other program-handling
> programs.

Me too! The thing is that the field of the real numbers is build on the
operators + and * which are associative and commutative. The neutral
elements are 0 and 1 respectively. The non-associative operators - and /
are defined in terms of the inverse elements. Thus \$a - \$b == \$a + (-\$b)
and \$a / \$b == \$a * (1/\$b) if \$b != 0. We could also bring in \$b**-1 as
another way to find the multiplicative inverse. But that just pulls in
yet another operator and the question which axioms apply to it and how
it is hyperated.

For user-defined numerical types---that is ones that provide +, *, -, /,
**, etc---I would hope that these axioms hold. Actually I hope that
there is a set of roles that define the standard numerics and enforce
sanity as far as that is possible via the class composition mechanics.

So coming back to your example, operator »-« would call -« on the RHS
and call »+« with the result. But I've no idea to which extent operator
» « is a special runtime operator versus a term re-writing at compile
time.
--
TSa (Thomas Sandlaß)

0 new messages