Programmer Maple

Avertissement:
• Maple est un langage de programmation de type impératif procédural. Il inclut aussi un certain nombre de fonctionnalités de la programmation fonctionnelle.
• Maple n'est pas fortement typé comme Pascal ou C, aucune déclaration n'est nécessaire. Mais les types existent. Le contrôle de type se fait à l'exécution et doit être programmé explicitement.
• Le langage de Maple est interprété, si bien que Maple n'est pas adapté à de gros programmes numériques. Les temps de calcul sont considérablement supérieurs à ce qu'ils seraient en C ou en Pascal.
I. Les structures de contrôle
1. Structures conditionnelles
La structure conditionnelle en Maple a la syntaxe suivante (les expressions entre crochets sont facultatives).
	if expr_1   then   suite_d'instructions
		[ elif  expr_i   then suite_d'instructions ]  ( 0, 1 ou plusieurs fois)
		[ else  suite_d'instructions  ]
	fi
Les expressions expr_1  et expr_i   (si les parties elif existent) sont évaluées tout à tour en tant qu'expressions booléennes. Si l'une d'entre elles s'évalue en true, alors la suite_d'expressions  correspondante est exécutée et l'expression conditionnelle renvoie NULL (c'est à dire rien). Si aucune d'entre elles ne s'évalue en true, la suite_d'instructions  qui suit le else est exécutée si elle existe. Dans les autres cas, aucune suite d'instructions n'est exécutée. Dans tous les cas, l'expression conditionnelle renvoie NULL. On voit donc que le mot clé elif correspond en gros à une contraction de else if (mais un tel else if nécessiterait un fi pour le terminer contrairement à elif).
Exemple d'expression conditionnelle:
if x>0 then 1 elif x=0 then 0 else 1 fi

Remarque  : le fait que la structure conditionnelle renvoie NULL fait qu'une structure conditionnelle n'est pas une expression algébrique et ne peut donc être utilisée pour une affectation. C'est ainsi qu'on ne peut pas écrire
y:=if x>0 then 1 elif x=0 then 0 else 1 fi

(ce qui est bien dommage). Par contre rien n'empêche une ou plusieurs instructions du corps de la structure de déposer des expressions sur la pile d'évaluation qui pourront être récupérés par les habituels  ", ""  et """. On peut par exemple écrire
if x>0 then 1 elif x=0 then 0 else 1 fi;
y:=";
2. Structure répétitive
Maple possède une unique structure répétitive, mais particulièrement riche puisqu'elle regroupe à la fois la structure for et la structure while de Pascal. Elle se présente sous la forme (là encore les parties entre crochets sont facultatives)
	[ for nom ] [ from debut  ] [to fin ] [ by pas  ] [ while condition ]
		do  suite_d'instructions   od
où
	- nom   doit désigner un nom (variable non affectée)
	- debut,  fin  et pas   doivent s'évaluer en des nombres entiers ou réels
	- condition  est une expression booléenne
Dans le cas où l'une des sous-structures est manquante, Maple utilise pour cette sous structure une valeur par défaut
	- nom  désigne par défaut une variable interne à Maple
	- debut  vaut par défaut 1
	- fin  vaut  par défaut l'infini
	- pas  vaut par défaut 1
	- condition   vaut  par défaut true.
La boucle est exécutée tant que name ≤ fin  et que condition   s'évalue en true, en donnant initialement à  name  la valeur  debut   puis en l'incrémentant de pas  à chaque nouvelle exécution de la boucle. Le test intervient toujours avant exécution du corps de la boucle (celui ci peut donc ne jamais être effectué si debut > fin  ou si condition  ne s'évalue pas initialement en true). L'expression itérative renvoie toujours NULL (cf le paragraphe sur la sémantique du langage), mais les évaluations qui interviennent au cours de l'exécution de la boucle contribuent à remplir la pile d'évaluation. Les expressions ainsi obtenues peuvent être retrouvées pour les trois dernières grâce aux ","" et """ habituels.
Exemple: recherche du plus petit nombre premier supérieur à 108
for i from 10^8+1 by 2 while not isprime(i) do od;print(i);
L'exemple précédent montre d'ailleurs que la valeur de l'indice de boucle est accessible après la fin de l'exécution de la boucle. Comme en C, Maple dispose d'instructions permettant de modifier l'exécution de la boucle
	break sort immédiatement de la boucle
	continue passe immédiatement à l'itération suivante (en commençant par le test).

Maple dispose d'une variante de for qui permet d'utiliser successivement les différents opérandes d'une expression sous la forme
for  name  in expr   while condition  do suite_d'instructions  od
qui est équivalente à
for i  from 1 to nops(expr  ) while condition  do  
	name :=op(i,expr ); suite_d'instructions;  od;
en se souvenant que la fonction nops renvoie le nombre d'opérandes d'une expression et que op(i,…) renvoie son i-ième opérande. Cette variante est particulièrement utile pour utiliser tour à tour les différents éléments d'une liste ou d'une séquence, mais ce n'est pas son seul usage.
Exemple: impression des carrés d'une liste d'expressions
for x in maListe do print(x^2);

Remarque : au moment où vous êtes tentés d'utiliser une structure répétitive en Maple, n'oubliez pas que Maple dispose également de fonctions répétitives qui sont souvent plus commodes et plus efficaces, les principales étant  seq, sum, prod et  $.
II. Les procédures
1. Les objets procédures
Contrairement à d'autres langages de programmation comme Pascal (mais comme en C), les procédures sont en Maple des objets comme les autres et elles peuvent donc faire l'objet d'affectations. L'objet procedure a la syntaxe suivante (les parties entre crochets sont facultatives comme d'habitude)

	proc(sequence_de_parametres  )
		[ local  sequence_de_noms  ; ]
		[ options sequence _de_noms ; ]
		suite_d'instructions 
	end

Les parametres forment une sequence (éventuellement vide), le corps de la procédure est une suite d'instructions séparés par des points-virgules. Les noms des variables locales sont listés après le mot clé local. Ils forment aussi une séquence, c'est à dire qu'ils sont séparés par des virgules. Comme les noms Maple, ces variables locales ne sont pas typées. Nous reviendrons plus tard sur les options et leur utilité.
	Les procédures Maple sont plus des fonctions au sens de C (qui peuvent éventuellement renvoyer NULL) que des procédures au sens de PASCAL. Une procédure Maple renvoie en fait la dernière valeur déposée sur la pile d'évaluation interne de la procédure (cf le paragraphe sur la sémantique du langage) au cours de l'exécution de la procédure, à moins que l'exécutions de la procédure n'ait exigé explicitement de retourner une expression à l'aide de la fonction RETURN.
Exemple : une procédure simple qui, étant donnés x et y, calcule x^2+y^2
proc(x,y)  x^2+y^2  end

L'exécution de la procédure entrainera la dépose sur la pile d'évaluation de la procédure de l'expression x^2+y^2, qui sera la valeur retournée par la procédure (qui est donc une fonction au sens habituel des langages de programmation). Ainsi vous pouvez écrire
z:=proc(x,y)  x^2+y^2  end (2,3);

et à la variable z sera affectée la valeur 22+32, qui est la valeur déposée sur le sommet de la pile d'évaluation au cours de l'exécution de la procédure.
	Par contre une exécution de l'instruction RETURN(expr ) entraîne une interruption immédiate de la procédure qui renvoie alors comme valeur l'évaluation de l'expression expr. 
FUNCTION: RETURN - explicit return from a procedure
CALLING SEQUENCE:
   RETURN(expr_1, expr_2, ...)
  PARAMETERS:
   expr_1, ... - expression sequence (possibly null)
 SYNOPSIS:   
- A call to the RETURN function causes an immediate return to the point where the current procedure was invoked.
- If return is via the RETURN function then the value of the procedure invocation is the expression sequence specified in the call to RETURN.

Exemple de retour explicite: une fonction qui teste la présence d'un élément dans une liste peut avoir la forme suivante
MEMBER:= proc(x,L) local v;
	for v in L do  
		if v=x then  RETURN(true)  fi
	od;
	false
end;

Si l'élément x est dans la liste L, au moment où  v=x deviendra vrai, l'exécution de l'instruction RETURN(true) entraînera l'interruption de la procédure qui renverra la valeur true. Si par contre x n'est pas dans la liste, la boucle s'achèvera normalement puis l'exécution de la dernière ligne de la procédure entraînera la dépose de false sur le sommet de la pile d'évaluation, et ce sera donc cette valeur qui sera retournée.
Attention: vous devez veiller à ne pas renvoyer comme résultat un objet local à la procédure. C'est en principe impossible puisque vous pouvez retourner soit le sommet de la pile d'évaluation (qui est évalué et qui est donc en général une valeur et non un objet), soit la valeur de l'objet passé à RETURN. En fait la situation est un peu plus compliquée à cause des règles d'évaluation propres à Maple concernant l'évaluation standard des tables (donc par exemple des vecteurs ou matrices) et des procédures. En effet l'évaluation standard de ces objets se fait en le dernier nom rencontré. Pour peu que ce nom soit local à la procédure, on risque de gros ennuis. Un moyen simple de forcer un retour de la valeur de l'objet (et nom de son nom) est de forcer une évaluation complête à l'aide de la fonction eval. Autrement dit, si objet   est l'objet que vous voulez renvoyer comme valeur de la procédure et qu'il est de type table  ou  proc , il faut déposer sur le sommet de la pile non pas objet , mais eval(objet  )  ou utiliser un retour explicite  RETURN(eval(objet  )).
	Une possibilité de sortie est donnée par l'instruction ERROR(message ), qui entraîne non seulement une interruption de la procédure, mais également de toute l'exécution normale de Maple et l'émission d'un message d'erreur  message  (une chaîne de caractères entre ` (backquote ou accent grave). Si ce message n'est pas intercepté par une instruction traperror, il entraîne une interruption de l'exécution de Maple.
FUNCTION: ERROR - error return from a procedure
CALLING SEQUENCE:
   ERROR(expr_1, expr_2, ...)
PARAMETERS:
   expr_1, ... - expression sequence (possibly null)
SYNOPSIS:   
- A call to the ERROR function causes an immediate return to the point where the current procedure was invoked.
- If the procedure was not invoked within the context of traperror then control  returns to the top level of the Maple system and the following message is  printed: ``Error, <in procname>'' followed by the evaluated expression sequence specified in the call to ERROR.  (Here, procname will be the name  with which the procedure was invoked).
- If the procedure was invoked within the context of traperror then the value  of the global name lasterror is assigned the evaluated expression sequence specified in the call to ERROR.  In this case, the value of the traperror call is also this same expression sequence.

Bien entendu, si, comme c'est le cas le plus ouvent, vous voulez utiliser plusieurs fois une procédure, vous commencerez par affecter l'objet procédure à une variable Maple. C'est ainsi que vous pourrez écrire
sommeCarres:=proc(x,y) x^2+y^2 end;

et que vous diposerez ainsi d'une nouvelle fonction Maple que vous pourrez utiliser à votre gré comme toute autre fonction.
z:=sommeCarres(2,3);
P:=sommeCarres(sin(u),cos(u));
xyz:=sommeCarres((1+x+y)^2,x*y);
2. Paramètres et variables locales
Une erreur commune en Maple est de traiter les paramètres des procédures comme des variables locales comme on peut le faire en Pascal ou en C. Ce n'est pas du tout le cas: ces paramètres ne sont pas des variables locales. En fait ce ne sont pas des variables du tout mais uniquement des containers destinés à recevoir les valeurs des paramètres qui seront passés à la procédure. 
	Lors de l'appel d'une procédure f  qui dépend des paramètres  x1,…,xn, avec des paramètres effectifs  p1,…,pn (c'est à dire lors de l'exécution de  f(p1,…,pn) où f est définie par  f:=proc(x1,…,xn) …  end), Maple commence par évaluer tous les paramètres p1,…,pn, puis il prend l'objet procédure f et dans cet objet, il commence par remplacer toutes les occurrences de x1,…,xn  par les valeurs de p1,…,pn. C'est seulement ensuite qu'il exécute la suite d'instructions. On voit donc que lors de l'exécution du corps de la procédure, les "variables"  x1,…,xn ont disparu.
Exemple d'une procédure erronée: 
f:=proc(x)  x:=x-1; RETURN(x^2)  end
(le RETURN n'est pas nécessaire, il est là pour la clarté). 
	Lors de l'exécution de t:=3; f(t), Maple commence par évaluer le paramètre effectif t (valeur 3), puis il prend l'objet f  et substitue tout au long de f la valeur 3 au paramètre x. Le corps de la procédure devient alors  3:=3-1; RETURN(3^2) et comme la première affectation n'a pas de sens, son exécution provoquera une erreur.
	Si l'on souhaite donc utiliser, comme on le fait couramment en Pascal ou en C, des paramètres comme variables locales, il faut donc commencer par recopier ces paramètres dans des variables locales. La procédure précédente deviendrait (bêtement)
f:=proc(x) local xloc;
	xloc:=x; xloc:=xloc-1; RETURN(xloc^2)  
   end
3. Nombre de paramètres
Toute procédure Maple peut en fait recevoir un nombre variable de paramètres, c'est à dire qu'aucune vérification n'est faite au moment de l'exécution d'une procédure que le nombre de paramètres passés à la procédure est le même que celui déclaré lors de la définition de la procédure. Simplement, si on déclare   f:=proc(x1,…,xn) … end  et si on appelle  f(y1,…,yp), le processus de substitution de  xi  par la valeur de  yi  va se poursuivre de la gauche vers la droite jusqu'à épuisement de l'une des deux séquences, et il va alors s'interrompre. Ensuite a lieu l'exécution du corps de la procédure. Si  n  et  p sont différents, deux cas peuvent alors se produire:
- si le nombre p  de  paramètres effectifs est inférieur au nombre  n  de paramètres déclarés, tout se passera bien si lors de l'exécution du corps de la procédure aucun des paramètres  formels xi  surnuméraire n'est utilisé; sinon on aura une erreur à l'exécution
- si le nombre p  de  paramètres effectifs est supérieur au nombre  n  de paramètres déclarés, il n'y aura pas d'erreur, mais les paramètres  yi  surnuméraires ne seront pas accessibles à travers les paramètres formels xi.
	Bien entendu, cette dernière possibilité serait sans intérêt si la procédure n'avait pas un autre moyen de récupérer les paramètres  effectifs  yi  surnuméraires. Or ce moyen existe à l'aide de deux fonctions Maple. La première  nargs renvoie dans une procédure le nombre de paramètres effectifs lors de l'appel de la procédure, la seconde  args renvoie la séquence des paramètres effectifs transmis à la procédure. C'est ainsi que lors d'un appel  f(y1,y2,y3,y4), au cours de l'exécution du corps de la procédure, nargs renverra 4  et  args[i]  renverra la valeur de  yi.
HELP FOR: args --- the sequence of actual arguments passed to a procedure
HELP FOR: nargs --- the number of arguments passed to a procedure
 CALLING SEQUENCE:
   args or args[i] or args[i..j] and nargs
SYNOPSIS:   
- Within a procedure, the special name args has as its value the expression  sequence of actual arguments with which the procedure was called.
 - Using the selection operation on this expression sequence, it follows that  args[i] is the i'th actual argument, and args[i..j] is the sequence of the i'th through j'th arguments.
- Within a procedure, the special name nargs has as its value the number of  elements in the expression sequence args.
Exemple: une procédure de calcul du plus grand élément parmi un nombre quelconque pourrait être
MAX:= proc()
       local r,i;
           r := args[1];
           for i from 2 to nargs do  
			if r < args[i] then r := args[i] fi 
		  od;
           r
       end 

Cette procédure a 0 paramètres formels mais peut calculer le maximum de n'importe quel nombre de paramètres effectifs.
4. Le passage des paramètres
Comme on l'a vu, la passage des paramètres est toujours effectué par valeur (comme c'est toujours le cas en C, et comme c'est le cas par défaut en Pascal). Autrement dit les paramètres effectifs sont d'abord évalués, et c'est ensuite leur valeur qui est utilisée par la procédure. Cependant, rappelons nous que nous travaillons en calcul formel et que donc le résultat d'une évaluation peut être lui même une variable (c'est à dire un nom), qui est donc susceptible de recevoir une affectation au cours de l'exécution de la procédure, et on obtient un analogue du passage par variable de Pascal (ou du passage par référence de C++). C'est ainsi qu'il est tout à fait possible d'écrire une procédure
miseAUn:=proc(x)  x:=1  end

Tout se passera bien tant que l'on passera à la procédure un paramètre effectif dont l'évaluation est une lvalue (par exemple une variable non affectée). Par contre, on aura une erreur d'exécution si on fait des appels à  miseAUn(2) ou à  miseAUn(y+3). Un bon moyen de garantir la sécurité d'un passage par référence est de bloquer l'évaluation de la variable que l'on passe comme paramètre en la mettant entre apostrophes (l'évaluation d'une expression entre apostrophes consiste à enlever un niveau d'apostrophes) ou de provoquer une évaluation en un nom à l'aide de la fonction evaln (eval to a name). C'est ainsi que vous ne devriez jamais faire  MiseAUn(t) mais plutôt MiseAUn('t') ou  MiseAUn(evaln(t)). 
FUNCTION: evaln - evaluate to a name
CALLING SEQUENCE:
   evaln(expr)
PARAMETERS:
   expr - an expression
SYNOPSIS:   
- The evaln function is used to ``evaluate to a name'' or, more generally, to form an assignable object.  The name (assignable object) will not itself be evaluated.
- A typical example of its use would be divide(a,b,evaln(t[i])) where i is the  index of a for loop.
- If the expression is a simple name (i.e., a string) then the same effect can be achieved by using single quotes on the name.
- Evaln can be used on names, subscripts, function calls, and concatenations.

Attention: les règles de substitution décrites dans un paragraphe précédent font qu'il est tout à fait préférable qu'un paramètre passé par référence (ou plutôt par nom) ne reçoive qu'une unique affectation au cours de l'exécution du corps de la procédure. N'hesitez donc pas à utiliser des variables locales tout au long de la procédure et n'affectez les paramètres passés par nom que juste avant le retour de la procédure.
	Remarque:  à titre personnel, l'auteur de ces lignes recommande de ne pas faire usage de la possibilité de renvoyer des résultats à travers des paramètres passés par nom et au contraire de faire le plus possible usage d'un style de programmation fonctionnel. Alors qu'en Pascal  le passage de variable par référence s'impose à cause du type très limité des types de retour possible pour une fonction et qu'en C il s'impose par suite de l'impossibilité pratique de retourner plusieurs résultats à la fois, en Maple ce renvoi de résultats à travers des paramètres est presque toujours inutile puisqu'une fonction Maple peut renvoyer plusieurs résultats à la fois par l'intermédiaire d'une séquence de résultats. Le seul cas où il peut sembler utile d'utiliser un passage de paramètre par nom est celui de fonctions mathématiques qui calculent deux ou plusieurs objets mais n'en renvoient qu'un seul, l'autre étant le plus souvent sans intérêt. C'est ainsi que dans une division euclidienne, le reste est le plus souvent l'objet intéressant mais qu'on est amené au passage à calculer le quotient. Il peut être intéressant dans ce cas de récupérer le quotient par l'intermédiaire d'un paramètre passé par nom pour "le cas où … ". C'est ce que font quelques fonctions de la bibliothèque de Maple.

5. Type des paramètres
Comme toutes les variables Maple, les paramètres ne sont pas typés. Il y a néanmoins dans la dernière version de Maple une possibilité de faire une vérification automatique de type à l'exécution de la procédure par une syntaxe "à la Pascal"  x: type_x. C'est ainsi que si l'on écrit
succ:=proc(x:integer) x+1 end

l'exécution de la procédure avec tout paramètre qui ne serait pas de type integer provoquera une erreur. On peut par contre construire des procédures polymorphes (c'est à dire pouvant recevoir des paramètres de types différents tout en s'adaptant au type de ces paramètres) en testant à l'aide de la fonction type à l'intérieur de la procédure le type des paramètres et en s'adaptant à ce type.
Exemple:
PLUS:=proc(x,y)
   if type(x,numeric) and type(y,numeric) then
		RETURN(x+y)
  elif type(x,complex) and type(y, complex) then
		RETURN(evalc(x+y))
  elif type(x,matrix) and type(y,matrix) then
		RETURN(evalm(x+y))
  else ERROR(`erreur de type`)
end;
II. Les fonctions opérateurs
1. Fonctions flèches et fonctions angles
A côté du mode procédural précédemment défini, Maple dispose d'un moyen d'associer simplement un résultat à des paramètres à l'aide de deux modes équivalents à la notation mathématique
		(x1,…,xn) Æ expression(x1,…,xn).
Ces deux modes sont le mode "flèche" (arrow en anglais)
	(x1,…,xn) -> expression(x1,…,xn)
ou le mode "angle"
	< expression(x1,…,xn) | x1,…,xn >.
Ces deux expressions renvoient une application de l'ensemble des n-uplets d'expressions Maple dans l'ensemble des expressions Maple, c'est à dire que les lettres  x1,…,xn sont des lettres muettes. Comme en mathématique lorsqu'on définit l'application  
		f: x Æ sin(x2)
on pourra poser en Maple
f:=x->sin(x^2)
ou encore
f:= < sin(x^2) | x >.

	Maple permet également de construire une fonction à partir d'une expression algébrique en rendant un certain nombre de paramètres abstraits (méthode tirée du l-calcul) à l'aide de la fonction unapply
FUNCTION: unapply - returns an operator from an expression and arguments
CALLING SEQUENCE:
   unapply(expr,x,y,..)
PARAMETERS:
   expr   - any expression
   x,y,.. - variable names
SYNOPSIS:   
- The result of unapply(expr,x) is a functional operator.  If we apply this operator to x we get our original expression.
         unapply(expr,x)(x) ==> expr
- In particular, for a function f(x),
         unapply(f(x),x) ==> f
- Whenever it is desired to construct an operator using contents of variables or evaluated expressions, unapply should be used.
Exemple:
• f:=unapply(sin(x^2),x);
                                           2
                            f := x -> sin(x )

• f(y+1);
                                         2
                              sin((y + 1) )

	On prendra soin (comme on devrait toujours le faire en Mathématiques) de bien établir une distinction entre le nom de la fonction, la fonction elle-même et la valeur de la fonction en un point (ne confondez pas la fonction  x Æ sin x  avec la valeur de la fonction sinus au point x).
	Maple dispose d'un certain nombre d'opérations sur ces fonctions, la principale d'entre elle étant bien entendu la composition dénotée par l'opérateur @ (qui remplace donc dans Maple l'opérateur ∑ des Mathématiques) et son opérateur itéré @@ (correspondant à la puissance des Mathématiques, fn = f ∑ … ∑ f    n fois)
FUNCTION: @ - the composition operator
FUNCTION: @@ - the repeated composition operator
CALLING SEQUENCE:
   f @ g   
   f @@ n   
PARAMETERS:
   f, g - any functions
   n    - an integer
 SYNOPSIS:   
- @ is the function composition operator.
- @@ is the repeated function composition operator.
- If n is negative, the invfunc table is checked to see if it has an entry for f.  That is, if invfunc[f] = g, then f@@n --> g@@(-n).
Exemple:
• f:=x->sin(x^2): g:=x->cos(x^3): h:=g@f;
                                 h := g@f
• h(t);
                                       2 3
                              cos(sin(t ) )
Maple peut faire un certain nombre d'opérations sur les fonctions comme les dériver à l'aide de l'opérateur D (le résultat n'est pas toujours très lisible, à moins de l'appliquer à une variable)
• D(h);
                               3   2                 2
                (x -> - 3 sin(x ) x )@f (x -> 2 cos(x ) x)
• "(t);
                                2 3       2 2      2
                   - 6 sin(sin(t ) ) sin(t )  cos(t ) t

ou en faire des tracés graphiques (les différents plot, plot3d, implicitplot, …  acceptent, et même dans un certain sens préfèrent, des fonctions en entrée).
• plot(h,-Pi..Pi);

Remarque : la définition de fonctions opérateurs peut avoir besoin de faire appel à des variables locales comme dans la fonction mathématique
			(x,n) -> isu(i=1;n; xi) 
Aussi Maple autorise-t-il l'introduction de variables locales grâce à la notation en mode flèche
		parametres   -> local variables_locales ;   résultat
et en mode angle
		< résultat   |  parametres   |  variables locales  >.
On pourra ainsi poser indifféremment
f:=(x,n) -> local i;  sum(x^i,i=1..n);
ou
f:= < sum(x^i,i=1..n) | x,n | i >.
2. Un peu de programmation fonctionnelle
Un certain nombre de fonctions Maple attendent de façon essentielle des fonctions comme paramètre. Il en est ainsi par exemple de la fonction map qui applique une fonction donnée à tous les opérandes du premier niveau d'une expression algébrique (et en particulier à tous les éléments d'une liste, d'un ensemble ou d'une table)
• f:=x->sin(x^2):  map(f,[2,y+1,cos(t)]); 	map(f,2+cos(t));
                                      2             2
                  [sin(4), sin((y + 1) ), sin(cos(t) )]

                                             2
                          sin(4) + sin(cos(t) )
• maTable:=table([(1)=y+1,(2)=3]): map(f,maTable);
                          table([
                                             2
                              1 = sin((y + 1) )
                              2 = sin(9)
                          ])
	Bien entendu, il n'est nullement nécessaire de nommer la fonction pour l'utiliser et vous pouvez très bien utiliser map sous la forme
• map(x->sin(x^2),[2,y+1,cos(t)]);

La fonction map admet une syntaxe un peu plus générale pour les fonctions à plusieurs paramètres en donnant une valeur par défaut aux paramètres à partir du second.
FUNCTION: map - apply a procedure to each operand of an expression
 CALLING SEQUENCE:
   map(fcn, expr, arg_2, ..., arg_n)
PARAMETERS:
   fcn   - a procedure or a name
   expr  - any expression
   arg_i - (optional) further arguments to fcn
SYNOPSIS:   
- The map function applies fcn to the operands of expr.
- The i-th operand of expr is replaced by the result of applying fcn to the i-th operand.  This is done for all the operands of expr.
- For a table or array, fcn is applied to each element of the table or array.
- If fcn takes more than one argument, they are to be specified as additional arguments, arg_2, arg_3,..., arg_n, which are simply passed through as the second, third ,..., n-th arguments to fcn.
Vous pourrez également avoir besoin de la fonction select qui sélectionne des opérandes suivant un crière entré sous forme fonctionnelle
FUNCTION: select - selection from a list, set, sum, or product
CALLING SEQUENCE:
   select(f, expr)
   select(f, expr, b_1, ..., b_n)
PARAMETERS:
   f             - a Boolean-valued procedure
   expr          - a list, set, sum, or product
   b_1, ..., b_n - optional extra arguments
SYNOPSIS:   
- The function select keeps the operands of expr which satisfy the Boolean-
  valued procedure f, creating a new object of the same type as expr.  Those
  operands for which f does not return true are discarded.
- Additional arguments b_1, ..., b_n are passed to f.

Exemple: pour sélectionner tous les nombres premiers compris entre 100 et 200 on fera
• select(isprime,[$100..200]);
 [101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199]

3. La définition d'opérateurs infixes
On appelle opérateurs infixes des opérateurs unaires tels que +, -  qui se mettent devant leur opérande, ou binaires tels que  +, - , *, / , ^ , =, union, …  qui se mettent entre leurs  opérandes. Maple ne permet pas facilement de redéfinir ces opérateurs infixes initiaux, mais permet par contre d'en définir de nouveaux tout à loisir. Une seule règle est à respecter: ces opérateurs infixes doivent commencer par le symbole & et être suivis soit d'un unique symbole non alphanumérique, soit d'un nom Maple valide. On les définit alors ces opérateurs de manière préfixe sous la forme
		`&nom  ` :=  procédure ou fonction
et on les utilise sous la forme  &nom  parametre   pour un opérateur unaire et sous la forme    parametre1   &nom   parametre2    pour un opérateur binaire. C'est ainsi que pour définir le produit scalaire de deux listes vous pourrez poser
• `&scal`:=(l1,l2)->local i; 						sum(l1[i]*l2[i],i=1..nops(l1)):
• [x1,y1,z1] &scal [x2,y2,z2];

                          x1 x2 + y1 y2 + z1 z2

Vous pouvez même définir des propriétés de ces nouveaux opérateurs à l'aide de l'instruction define comme par exemple
•  define(`&+`, associative, commutative, identity=0);
• define(Ls, unary, type=[algebraic], Ls(0)=0, forall(x, Ls(exp(x))=Ls(x)+1, Ls(ln(x))=Ls(x)-1));

la première propriété garantissant que l'opérateur binaire  &+  est associatif, commutatif et possède 0 comme élément neutre (Maple procédera automatiquement aux simplifications nécessaires) et la deuxième que l'opérateur  Ls  est une fonction unaire qui ne s'applique qu'aux expressions algébriques et qui vérifie  Ls(0)=0 et  
"x , Ls(ex) = Ls(x)+1  et  Ls(log(x))=Ls(x)-1.
4. Exercices
Maple est un peu chiche de fonctions sur les listes. Pouvez vous définir en Maple les fonctions suivantes (qui font partie de la bibliothèque de base de Mathematica) d'une manière aussi fonctionnelle que possible
flatten :  doit transformer une liste de listes de listes …  en une unique liste en mettant tout à plat au premier niveau
nestlist : nestlist(f,x,n) doit engendrer une liste [x, f(x), f(f(x)), … ]
foldlist :  foldlist(f,x,[a,b,…]) doit retourner la liste [x, f(x,a), f(f(x,a),b),… ]
mapindexed:  mapindexed(f,[a,b,…]) doit retourner la liste [f(a,1), f(a,2),…]
mapthread:  mapthread(f,[[a1,a2,…],[b1,b2,…]) doit retourner la liste [f(a1,b1),f(a2,b2),…] ; essayez de la généraliser à un nombre quelconque de listes
outer :  outer(f,[a1,a2,…],[b1,b2,…])  doit retourner la "matrice" (liste de listes) des f(ai,bj); essayez de la généraliser à un nombre quelconque de listes
inner :  inner(f,[a1,a2,…],[b1,b2,…],g) doit retourner g(f(a1,b1),f(a2,b2),…) (quand f=*  et  g=+, on trouve le produit scalaire)

V. La récursivité et les options
Toute fonction Maple peut-être récursive. Des fonctions peuvent être mutuellement récursives sans qu'il soit nécessaire de se livrer à des gymnastiques de forward à la Pascal puisque les noms ne sont pas vérifiés au moment où l'on définit la fonction, mais au moment où on l'utilise. On pourra donc définir
• f:=proc(x)
		if x=0 then 1 else x*g(x-1);
  end;
  g:=proc(x)
        if x=0 then 1 else f(x-1)/x;
  end;

Maple dispose à cet égard d'une possibilité précieuse, c'est l'option remember. Lorsqu'une fonction est définie avec cette option, Maple lui associe une table de souvenance qui contient tous les appels de la fonction et les résultats trouvés. Si la fonction est de nouveau appelée avec les mêmes valeurs des paramètres, le résultat est directement retourné à partir de la table de souvenance sans que le corps de la fonction soit réexécuté. Cela peut entraîner des gains considérables en temps. C'est ainsi que les deux exemplaires suivants de la fonction de calcul des nombres de Fibonacci ont des complexités respectives (et donc des temps d'exécution respectifs) en 2n et  n:
• fib1(n):= proc(n) if n<=1 then 1 else 
 fib1(n-1)+fib1(n-2); end;
fib2(n):= proc(n) option remember; 
	if n<=1 then 1 else 
 		fib2(n-1)+fib2(n-2); end;

En effet la première procédure passe son temps à recalculer les mêmes valeurs alors que la deuxième ne les recalcule pas puisqu'elle les retrouve directement dans une table. Sur un mac Powerbook, la première procédure met 32 secondes pour calculer fib1(18) et la seconde 0,26 secondes pour calculer fib2(18) (les deux fournissant bien entendu le même résultat). La première utilise 70 kilooctets de mémoire et la seconde 675 octets.
	Bien entendu, méfiez vous des effets de bord sur le comportement des fonctions ayant des tables de souvenance. D'une part, il est délicat de savoir si le corps de la fonction sera exécuté ou non, et donc si un effet de bord souhaité aura lieu ou non. D'autre part, la table de souvenance ne tient pas compte de la modification éventuelle de variables globales entre deux appels. En particulier si vous appelez une première fois une telle fonction alors que la précision générale est fixée à 10 chiffres significatifs, que vous changez cette précision générale à l'aide de la variable Digits=30, puis que vous réappelez la fonction avec le même paramètre, le résultat ne sera pas recalculé et vous n'aurez toujours que vos 10 chiffres significatifs.
VI. Résumé de la syntaxe et de la sémantique du langage
	Nous présentons ici un résumé de la syntaxe et de la sémantique du langage. Pour simplifier nous avons convenu de confondre les notations infixes et préfixes des différents opérateurs
	a op  b op  … op  c  		est remplacé par 	op  (a,b,…,c)
que op    soit  +,-,*, / , ^, $ , @ , @@, .. (range )  ou un opérateur neutre &… .
	De même nous avons convenu de confondre les différentes formes des procédures ou fonctions
	brc}(a((x1,…,xN)->…; ;< … | x1,…xN>))  sont remplacés par  proc(x1,…,xN) option operator; …  end

Comme d'habitude l'opérateur "grammatical" d'affectation ::=   doit être lu comme un "est un" , le symbole |  désigne une alternative et les cochets encadrent des parties facultatives. Les expressions qui contrôlent l'exécution sans intervenir dans la valeur de retour n'ont pas été explicitées et remplacées par … .
	La première colonne décrit la syntaxe associée aux différents types d'expressions
	* générales    	expr
	* élémentaires    	elemexpr
	* indexées	indexexpr
	* composées	seqexpr
	* non évaluées	quotexpr
	* affectations	affexpr
	* conditionnelles	condexpr
	* répétitives	repexpr
	* procédurales	procexpr
	La deuxième colonne décrit la valeur de retour de l'évaluation de l'expression (que nous avons indiquée par une fonction fictive EV). Ne pas confondre cette valeur de retour de l'évaluation standard avec la valeur de retour de eval(elemexpr ) qui elle est la valeur de retour de l'évaluation complête (d'une expression élémentaire).

Syntaxe	valeur de retour de l'évaluation (désignée ici par EV(…))	effets de bord 	
expr::=  elemexpr | affexpr | seqexpr | condexpr | repexpr | procexpr 			
elemexpr::=  nombre | symbole | indexexpr | quotexpr | 
  elemexpr(elemexpr1,…,
		elemexprN)	le nombre, la valeur du symbole, la valeur de quotexpr ou de l'expression
EV(elemexpr)(EV(elemexpr1),…, EV(elemexprN))	empilement de la valeur  si ≠ NULL	
indexexpr::=  elemexpr[elemexpr1,…,
		elemexprN]	EV(elemexpr)[EV(elemexpr1),…, EV(elemexprN)]	empilement de la valeur si ≠ NULL	
quotexpr::=  'expr'	l'expression expr   elle même, non évaluée	l'expression expr   non évaluée est empilée	
affexpr::=  symbole:=elemexpr | indexexpr:=elemexpr	NULL	la valeur2 de elemexpr  n'est pas empilée mais affectée à symbol  ou à indexexpr  (au besoin en créant la table correspondante)	
seqexpr::=  expr1;…;exprN	NULL	empilement des  valeurs ≠NULL dans la pile d'évaluation à trois places (FIFO)	
cond_expr::=  if … then  seqexpr1 [elif … then seqexpr2] … [else seqexprN] fi	NULL	celui de la seqexpr  qui est évaluée	
rep_expr::= [for …] [from …] [to …] [by …] [while …] 
do seqexpr od	NULL	celui de la suite de seqexpr   qui est exécutée	
proc_expr::=  proc(…) [options …;]
[local …;]
     seqexpr
end	le sommet de la pile d'évaluation3  de  procexpr	à la sortie, la pile d'évaluation de procexpr est détruite; la valeur de retour est empilée si ≠ NULL