6.55 args and &-operators problem (2.12.97)

6.55.1 Rafal Ablamowicz
6.55.2 Stanley J Houghton(3.12.97)
6.55.3 Robert Israel(3.12.97)
6.55.4 Joseph Riel (3.12.97)
6.55.5 Burkhard Wald(4.12.97)
6.55.6 Jean GARRIGUES (4.12.97)
6.55.7 Philip Yasskin (8.12.97)

6.55.1 Rafal Ablamowicz

I have discovered a few annoying problems (bugs?) with ’args’ when defining &-operators. Below I can reproduce two problems, while the third one is elusive and appears randomly. I will address it too although I don’t have a verbatim Maple output to show. I would appreciate any hints how to avoid them, or to understand them.

Let’s define function `&t` as follows:

> `&t`:=proc() local L: L:=[args]; RETURN(L) end: 
> 
> K1 := `&t`(e1,e2,e3); 
                          K1 := [e1, e2, e3] 
> type(%,list(name)); 
                                 true
 

The above two answers are correct: [e1, e2, e3] is a list of names.

Here is the first problem:

> K := e1 &t e2 &t e3; 
                         K := [[e1, e2], e3]
 

Notice, that the output form has changed even though `&t` has not: unlike before, now the output is a list consisting of a list and a name (I suspect that this is a result of any &-operator being implicitly left-associative in Maple).

Next, Maple confirms that K is of the type [list,name] and that K is not of the type list(name) like K1 was:

> type(K,[list,name]); 
                                 true 
> type(K,list(name)); 
                                false
 

Given that the outputs K1 and K are different to me is illogical and for sure causes programming problems.

Here comes the second problem. I believe it is even worse than the first one: it has to do with the same type checking except now it will be done inside the procedure, not outside. For that purpose, I will slightly re-define `&t` and call it `&T` for the sake of discussion:

> `&T`:=proc() local L: L:=[args]; 
>       if type(L,list(name)) then RETURN(list_of_names) elif 
>          type(L,[list,name]) then RETURN(list_and_name) else 
>          ERROR(`wrong types`) fi end: 
> 
> `&T`(e1,e2,e3); 
                            list_of_names
 

This answer is correct and it has been expected since L=[args] is a list of name. Now please take a note of the following surprising result:

> e1 &T e2 &T e3; 
                            list_of_names
 

That is unexpected and different than before: K above was of the type [list,name] so why does Maple think now that [args] inside `&T` is of type list(name) when before clearly [args] was explicitly not of that type? What is going on? Why two different results from the type checking, one done inside and one done outside?

The third problem has to do with Maple returning sometimes [e1 &t e2, e3] instead of [[e1,e2],e3] in the first example. I have no clue why. Has anyone encountered this problem before?

PS I run Maple V R. 4 patch 4.00b April 16, 1996, under Windows NT and 95.

6.55.2 Stanley J Houghton(3.12.97)

As I understand it, when you apply `&t` as an applicative expression such as

   `&t`(e1,e2,e3)
 

you are applying the procedure to an argument list of three variables but when you do

   e1 &t e2 &t e3
 

you are applying the procedure to an argument list of two arguments (e1,e2) and then repeating the application of the procedure to (again to two arguments) the result of this operation and e3).

I comment further below and hope it helps

| Here is the first problem: ...

Your input is a equivalent to

   > K:= `&t`(`&t`(e1,e2),e3);
 

Hence the resulting nested list

| Here comes the second problem. ...

This is like requesting (again)

   >  `&t`(`&t`(e1,e2),e3);
 

which results in evaluation of `&t`(list_of_names,e3) which leads to the result you got.

6.55.3 Robert Israel(3.12.97)

| Here is the first problem: ...

The output has changed because the input has changed. In other words, Maple parses e1 &t e2 &t e3 as (e1 &t e2) &t e3 and does not automatically simplify it to `&t`(e1, e2, e3). Seems reasonable enough to me.

| Given that the outputs K1 and K are different to me is illogical ...

I don’t know what’s illogical about it. e1 &t e2 &t e3 and `&t`(e1, e2, e3) are different, that’s all. When used in infix form, a "&" operator is a binary operator, not a ternary operator.

If `&t`(e1,e2,e3) is what you want, then `&t`(e1,e2,e3) is what you have to say.

| Here comes the second problem. ...

Not at all surprising, and nothing to do with type checking. Remember that Maple parses the input as (e1 &T e2) &T e3. So first it calls &T with arguments e1 and e2. Since [e1,e2] is a list of names, the result of that is a name, namely "list_of_names". Then it calls &T with arguments list_of_names and e3, and since [list_of_names, e3] is a list of names it returns list_of_names.

| The third problem has to do with Maple returning sometimes ...

I have no idea why this would happen. It would mean that somehow the e1 &t e2 was not being evaluated. Are you sure that it happens in this example exactly as you gave it to us? I suspect that it is not "random", but that you have done something in your Maple session that caused e1 &t e2 to return unevaluated.

P.S. One thing that _is_ a bug, in my opinion, is that (if &q is unassigned) Maple prints both (a &q b) &q c and a &q (b &q c) as a &q b &q c (although the internal representations are different - you can use lprint to see that). For a non-associative operator this can lead to confusion.

6.55.4 Joseph Riel (3.12.97)

The following procedure does what you want (though I suspect your example was a simple model of the real problem).

`&t` := proc() map(proc(a) if a::list then a[] else a fi end, [args]) end:
 

| Here comes the second problem....

The reason is that you are returning list_of_names, not an actual list. What you should have done [to demonstrate the problem] is,

`&T`:=proc() 
local L: 
  L:=[args]; 
  if type(L,list(name)) then 
       print(list_of_names) 
  else print(list_and_name) fi; 
  L 
end:
 

now

a &T b &T c; 
                     list_of_names 
                     list_and_name 
                      [[a, b], c]
 

which is as expected.

6.55.5 Burkhard Wald(4.12.97)

| Here is the first problem: ...

A procedure with an &-name is not implicitly assocative. First take an unnassigned operator name &A . You can write

> x &A y; 
           x &A y 
instead of 
 
> `&A`(x,y); 
           x &A y 
You also can write 
 
> x &A y &A z; 
          x &A y &A z
 

which is interpreted as `&A`(`&A(x,y),z) which is different from `&A`(x,y,z).

Compare the following.

> eq:=(x &A y) &A z = x &A (y &A z); 
           x &A y &A z = x &A y &A z
 

The echo on the screen let us thing that the equation is true. Not so.

> evalb(eq); 
           false 
 
> op(lhs(eq)); 
        x &A y, z 
 
> op(rhs(eq)); 
        x, y &A z
 

Now you can understand what happends in your second example.

&T is called twice. First with the arguments e1,e2 and second with the arguments list_of_names,e3 . Of cource &T returns again list_of_names .

| The third problem has to do with Maple returning sometimes ...

For example

> 'e1 &t e2' &t e3;
 

gives

   [e1 &t e2, e3]
                                                                                    
                                                                                    
 

I think your above operators are only pre-examples and what you really want to do is more complex. May be, I can give you some hints, if you say a bit more about your goals.

6.55.6 Jean GARRIGUES (4.12.97)

| Here is the first problem: ...

The result seems to me correct. It prooves that Maple interpret "e1 &t e2 &t e3" as "(e1 &t e2) &t e3". Expressions are interpreted from left to right. The second "&t" receives [e1,e2] as first argument and e3 as second argument.

I assume you want a "concatenation". The following &t returns a sequence instead of a list

> restart: 
> `&t`:=proc() local L: L:=args; RETURN(L) end: 
> K1:=[e1 &t e2]; 
      K1 := [e1, e2] 
 
> K2:=[e1 &t e2 &t e3]; 
      K2 := [e1, e2, e3]
 

| Here comes the second problem. ...

Why surprising ? Maple interpret "e1 &T e2 &T e3" as "(e1 &T e2) &T e3". The result of (e1 &T e2) is the string "list_of_names" ...

6.55.7 Philip Yasskin (8.12.97)

Problem 1:

The difference between &t(e1,e2,e2) and e1 &t e2 &t e3 is that the first calls &t once while the second calls &t twice.

Problem 2:

Try putting a trace into the procedure:

 `&T`:=proc() option trace: local L: L:=[args]; 
       if type(L,list(name)) then RETURN(list_of_names) elif 
       type(L,[list,name]) then RETURN(list_and_name) else 
       ERROR(`wrong types`) fi end:
 

Then you get:

> &T(e1,e2,e3); 
{--> enter &T, args = e1, e2, e3 
 
                          L := [e1, e2, e3] 
 
<-- exit &T (now at top level) = list_of_names} 
 
                            list_of_names
 

and

> e1 &T e2 &T e3; 
{--> enter &T, args = e1, e2 
 
                            L := [e1, e2] 
 
<-- exit &T (now at top level) = list_of_names} 
{--> enter &T, args = list_of_names, e3 
 
                       L := [list_of_names, e3] 
 
<-- exit &T (now at top level) = list_of_names} 
 
                            list_of_names
 

Clearly in e1 &T e2 &T e3 there were two calls to &T. The first time it returned "list_of names" as it should; the second time "list_of names" was the first argument which is itself a name, so the result "list_of names" is correct.