Is there a switch/case statement in Maple? So that instead of:
if (a = a1) then
b1
elif (a = a2) then
b2
elif (a = a3) then
b3
end if
Something like:
switch (a) {
case: a1 {b1}
case: a2 {b2}
case: a3 {b3}
}
???
I'm potentially going to have a long list of elif's and might need more efficient way of doing it.
caseless
There is no switch/case statement in Maple. Use the if then construct. For clarity I occasionally swap the left and right sides of the equation so that the case shows up first:
Maple NOT switch!
Maple NOT switch!
There is goto though :) So you could use something like
a:=a2: proc() local k; if member(a,[a1,a2,a3],k) then goto(k) else return fi; 1: b1; return 1; 2: b2; return 2; 3: b3; return 3; end(); 2Alec
looks great
Thanks, Alec,
I think this will do just what I need.
efficient?
If you are looking for something more efficient than if/then, goto is probably not it. I am fairly certain there is a reason that Maple's goto is undocumented and, as far as I know, not used anywhere in the library.
John
maybe
That has been my understanding---the goto implementation is not particularly efficient---however, I've also learned that testing frequently reveals errors in the received view. In this case, it is easy enough to demonstrate a simple implementation in which, for some inputs, the goto statement is no less efficient. Compare the following three alternative implementation of a case statement:
f1 := proc(a) local b,k; if a in '[a1,a2,a3,a4,a5,a6,a7,a8,a9]' then do goto(a); a1: b := 1; break; a2: b := 2; break; a3: b := 3; break; a4: b := 4; break; a5: b := 5; break; a6: b := 6; break; a7: b := 7; break; a8: b := 8; break; a9: b := 9; break; end do; else b := 10; end if; b; end proc: f2 := proc(a) local b; if 'a1' = a then b := 1; elif 'a2' = a then b := 2; elif 'a3' = a then b := 3; elif 'a4' = a then b := 4; elif 'a5' = a then b := 5; elif 'a6' = a then b := 6; elif 'a7' = a then b := 7; elif 'a8' = a then b := 8; elif 'a9' = a then b := 9; else b := 10; end if; b; end proc: f3 := proc(a) local b; try error sprintf("%a", a); catch "a1": b := 1; catch "a2": b := 2; catch "a3": b := 3; catch "a4": b := 4; catch "a5": b := 5; catch "a6": b := 6; catch "a7": b := 7; catch "a8": b := 8; catch "a9": b := 9; catch: b := 10; end try; b; end proc:Here we measure the time required for each:
For inputs that require more than about 7 comparisons, the goto method is equivalent to if/elif. The try/catch technique was mainly for comparion.
I'm not suggesting that goto should be used---there are reasons other than speed that it might not be a good idea.
Horror, not efficiency
The reason, AFAIK, that goto was never documented was the collective horror that it existed at all (it was not implemented by Maplesoft). Maple has enough mis-features as it is, there is no need to encourage users to make their code worse still.
piecewise
You could use the piecewise function, like this:
table
I had assumed that the b1, b2, etc. represented code. If they are actually just expressions, then a better way to do this would be with a preassigned table:
T := table([a1=b1, a2=b2, ... ]);
R := `if`(assigned(T[a])
, T[a]
, some_other_value
);
Question on 'piecewise'
(sorry, do not have Maple installed here ...)
piecewise evaluates
piecewise evaluates arguments only as needed.
The prototypical example is
If all arguments were evaluated when piecewise is called with x=0, this would produce an error. But, it doesn't.
Doug
no, it's code
The tokens that the b's represent are code. I'm looking for a decision making mechanism. Basically:
proc(arg1, arg2, calculationType, _rest)
calculationTypes := [type1, type1, type3, etc];
if member(calculationType, calculationTypes, k) then goto(k) else return end if;
1: do this calculation with arg1 and arg2
return;
2: do a different calculation with arg1 and arg2
return;
3: do still something different
return;
Im abstracting a lot of logic out to a single function call, and this proc will handle doling out the proper heavy lifting based on the type of calculation specified....
Types and overload
In case if type1, type2, type3 etc. are Maple types, the standard way of doing that would be with overload,
f := overload([ proc(arg1, arg2::type1) option overload; b1 end, proc(arg1, arg2::type2) option overload; b2 end, proc(arg1, arg2::type3) option overload; b3 end])I wouldn't use goto myself (first, because of its bad reputation, and second, because it might disappear in the next Maple version.)
A "real life" example - in my Binary Arithmetic package.
Alec
not maple types
Unfortunately, my abstraction layer breaks down pretty quickly if I restrict myself to Maple types instead of made-up ones. If Goto goes the way of non-rectangular implicitplots, we could be in trouble...
satisfies
There is such a type as satisfies which can fit practically anything, see
?type,satisfies .
Also, made-up types can be added using TypeTools package.
Edit: Just wanted to add few words about goto. If you decide to use it, be prepared that (some, management type) people looking at your code would think: "serpentine code - has no idea about structured programming" - that's the main reason why programmers usually avoid using goto at all costs - even if the code with goto could be 10 times more efficient and more clear than without it. Overloading, on the other hand, looks like a modern technique - everybody knows that it was introduced in C++ which made it a better language than C.
Alec
i hear you on the structure...
Yeah, the goto's make me cringe for that very same reason. Don't know how much is gained by adding my own Maple types, though. For now, I only have 5 possibilities, so I'll probably stick with goto for now and refactor once I hit 10.
identical
This reply is probably obsolete for now for Wolfie7873, the original author of the post, who has already indicated that goto is good enough for now, but I thought I'd just add this for future reference.
If you would be looking to replicate the switch/case statement found in other languages as closely as possible, so you have some literal constants a1, a2, a3 that you are comparing to, and you would want to use overload, then the most useful class of types would be the "identical" types - see type,identical. An example mirroring the initial construct in the post:
overload([ proc(x :: identical(a1)) option overload; b1; end, proc(x :: identical(a2)) option overload; b2; end, proc(x :: identical(a3)) option overload; b3; end])(a);Now if you have really many cases, and care about efficiency, there is usually some structure to the set of possible values for a: at least an ordering or so. Then this is certainly a bad way to do it: it would simply try whether a is equal to a1 first, then a2, et cetera. What you'd want to do is use the structure; in this case, use binary search for the value. That would require writing some custom code.
Overload and switch
I should say that I didn't check the efficiency, but code with goto looks much more clear than with overload. Actually, even if ... elif looks better :)
I wonder why Maple doesn't have a switch? It is a standard recommendation for writing a good (maintainable) code - to use a switch instead of nested ifs.
Alec
Tables
Personally, I tend to use a table-of-functions (a generalization of Joe's answer) when I need a 'switch' statement in Maple. If you provide us with a somewhat more realistic example, I am sure we could come up with a nice way to do it. I have had rather good success with these tables-of-functions.