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.
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.
| 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.
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.
| 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.
| 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"
...
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.