3

I have a procedure

f:=proc(x,option1,option2) ... end proc;

In my case option1 is always an integer and option2 is either a list or something else (including integer). Both options are optional, so these commands work as expected:

f(x);
f(x,3);
f(x,4,[1,2]);
f(x,5,3);
f(x,6,expand);

But if option1 isn't specified then I don't know an easy way to deal with it since Maple doesn't allow the usage like

f(x,,3);
f(x,,[1,2]);

I can make it understand

f(x,[1,2]);

but I still have a problem with

f(x,3);

since it's not clear if 3 is option1 or option2. I can rewrite the code to understand function calls in this format

f(x,[1,option1],[2,option2]);
f(x,[1,option1]);
f(x,[2,option2]);

but I'm curious if there is a simpler way to achieve that since for some Maple functions (like plot) the order of most options doesn't matter.

Robai
  • 197
  • 9

3 Answers3

3

Use keyword arguments.

f:=proc(x,{op1::integer:=0,op2::{list,integer}:={}},$)

   if has([_passed],'op1') then
      print("op1 =",op1);
   else
      print("op1 not passed");
   fi;

   if has([_passed],'op2') then
      print("op2 =",op2);
   else
      print("op2 not passed");
   fi;

    #rest of code
end proc;

Now you can do

f(x,'op2'=[1,2,3])    
                        "op1 not passed"    
                       "op2 =", [1, 2, 3]

And

f(x,'op1'=99)
                          "op1 =", 99
                        "op2 not passed"

And

f(x)
                        "op1 not passed"    
                        "op2 not passed"

And

f(x,'op1'=99,'op2'=[1,2,3])
                          "op1 =", 99
                       "op2 =", [1, 2, 3]

And

f(x,'op1'=99,'op2'=19827)
                          "op1 =", 99
                         "op2 =", 19827

Make sure to use 'op1'=value when calling, and not op1=value

Nasser
  • 12,849
  • 6
  • 52
  • 104
3

As others already mentioned one solution is using "kwarg" (keyword argument). You can also use _passed or _rest. You can read more in Maple help pages or Maple programming guide (https://www.maplesoft.com/documentation_center/Maple2021/ProgrammingGuide.pdf).

Here is just an example how you can use them. _passed is for when you want to say whatever that has been passed to your procedure, and _rest is for whatever that has been passed to your procedure except the ones that are already assigned to the parameters you mentioned inside the parentheses in front of proc. Let's say we want to define a procedure with 1 necessary argument and possible 2 optional arguments. If there are two optional arguments given, we assume the first one is always option1 and the second one is option2, but if only one optional argument is given, then depending on if it is of type integer or not it will be option1 or option2 respectively.

To ask the number of passed or the rest of passed arguments you can use _npassed and _nrest. And the command assigned() checks if something is assigned a value or not. You can check if something is of a specific type, by type(-,-) or - :: -. So here is the simple code.

test := proc( x )
    local option1, option2:
    if _nrest = 2 then
        option1 := _rest[1]:
        option2 := _rest[2]:
    elif _nrest = 1 then
        if _rest[1] :: integer then
            option1 := _rest[1]:
        else
            option2 := _rest[1]:
        end if:
    end if:
    printf( "necessary argument is %a\n", x ):
    if assigned( option1 ) then
        printf( "option 1 is given and is %d\n", option1 ):
    end if:
    if assigned( option2 ) then
        printf( "option 2 is given and is %a\n", option2 ):
    end if:
end proc:

Here is a screenshot of the output of the above procedure for different inputs.

enter image description here

2

Most of the plotting commands use Maple's more modern argument-processing to manage procedure options.

In particular most options to plotting commands are provided as so-called keyword options. That automatically provides the functionlity in which the location (of such options) doesn't matter.

For example,

f:=proc(v, 
        {ord::{integer,NoUserValue}:=':-NoUserValue'},
        {special::{integer,list,NoUserValue}:=':-NoUserValue'});

  print(':-ord'=ord, ':-special'=special);

end proc:

f(x);

    ord = NoUserValue, special = NoUserValue

f(x,ord=3);

         ord = 3, special = NoUserValue

f(x,special=5);

         ord = NoUserValue, special = 5

f(x,special=5,ord=3);

               ord = 3, special = 5

f(x,ord=3,special=5);

               ord = 3, special = 5

As you've noticed, you [logically] cannot use multiple *positional/ordered" parameters if both have the same type and some earlier ones are missing.

If you really wanted you could make one of those options into a positional parameter, although naturally that would lose its flexibility of arbitrary placement. For example,

restart;
f2:=proc(v, 
        ord::{integer,NoUserValue}:=':-NoUserValue',
        {special::{integer,list,NoUserValue}:=':-NoUserValue'});

  print(':-ord'=ord, ':-special'=special);

end proc:
f2(x);
f2(x,3);
f2(x,special=5);
f2(x,special=5,3);
f2(x,3,special=5);

restart;
f3:=proc(v, 
         special::{integer,list,NoUserValue}:=':-NoUserValue',
         {ord::{integer,NoUserValue}:=':-NoUserValue'});

  print(':-ord'=ord, ':-special'=special);

end proc:
f3(x);
f3(x,5);
f3(x,ord=3);
f3(x,ord=3,5);
f3(x,5,ord=3);

There are too many variants to show them all here, sensibly.

You don't have to use the name "NoUserValue" as the default values.

acer
  • 6,671
  • 15
  • 15