2.9 Introduction aux fonctions

Il est courant en programmation que l'on chercher à répéter les mêmes instructions à différents endroits d'un programme. Il est alors pratique de regrouper ces instructions au sein d'une fonction. Chaque fois que l'on aura besoin de réaliser cet ensemble d'opérations, il suffira d'appeler la fonction que l'on aura crée pour cela.

Nous avons déjà rencontrés plusieurs fonctions en R, comme typeof() qui nous donne le type d'un objet, ou print() qui affiche quelque chose dans la console. Mais il arrive souvent que l'on souhaite faire quelque chose pour lequel R ne propose pas de fonction existante. Nous devons alors créer nos propres fonctions.

Créer notre première fonction

Une fonction en R se construit selon la syntaxe suivante :

ma_fonction = function(parametre1, parametre2) {
    #Code à exécuter
    return(resultat)
}

Décomposons cette structure ensemble. ma_fonction est le nom que l'on va donner à la fonction. Plus précisément, c'est le nom de la variable qui contiendra notre fonction. La fonction est affectée à la variable via l'opérateur d'affection = .

Le mot clef function sert à indique à R que l'on souhaite créer une fonction. Entre les parenthèses (), on indique le nom des différents paramétres de la fonction, sépérés entre eux par des virgules . Entre {} se trouve le corps de la fonction, qui contient les instructions qui seront exécutée par cette fonction. Enfin, la dernière ligne du corps d'une fonction est toujours return() , qui indique ce que la fonction doit renvoyer.

Construisons une fonction addition() qui additionne deux nombres et renvoit le résultat :

addition = function(nombre1, nombre2) {
    resultat = nombre1 + nombre2
    return(resultat)
}

Nous avons crée une fonction addition() qui prend en entrée deux paramétres nombre1 et nombre2 et qui retourne la somme de ceux deux nombres.

On peut utiliser dans le corps de la fonction les différents paramétres de la fonction : R va automatiquement créer des variables avec le nom des paramétres, qui contienderons les valeurs qui seront spécifiées lors de l'utilisation de la fonction. On peut alors y réaliser la suite d'instruction que l'on veut. Sans oublier de préciser de renvoyer quelque chose à la fin avec return() .

Remarque : Notre fonction comporte ici deux paramètres, mais une fonction peut avoir autant de paramétres que l'on souhaite. Il suffit de bien les séparer entre eux par une virugle. Une fonction peut aussi d'avoir aucun paramétre, bien que ça soit plus rare.

Appeler notre fonction

Maintenant que nous avons notre premiére fonction, comment l'utiliser ? Pour appeler notre fonction, il suffit d'écrire le nom de la variable qui la contient, suivit imédiatement de () . Si la fonction posséde des paramétres, on doit alors indiquer les valeurs qu'ils doivent recevoir entre les parenthéses :

#On appelle notre fonction addition :
addition(2,3) #affiche 5

Les éléments que l'on passe à la fonction entre les parenthèses sont appellés les arguments de la fonction. On dit que l'on passe les nombres 2 et 3 en arguments à la fonction addition() . Les arguments seront alors associés aux paramétres correspondants.

Voici ce qui se passe en détail quand on éxecute l'instruction addition(2,3) . R va d'abord créer des variables qui ont le même nom que ceux des différents paramétres de la fonction. Ici, il va créer une variable nombre1 et une variable nombre2 . Puis il va affecter à ces variables les donnés que l'on a passé en argument. Le premiére paramétre va ainsi recevoir le premier argument utilisé, le second paramétre le second argument, etc. Ici, nombre1va recevoir le premier argument qui est le nombre 2 ; et nombre2 va recevoir le second argument qui est 3 .
Une fois cela fait, R va exécuter les instructions contenues dans le corps de la fonction, et renvoyer quelque chose à la fin à l'aide de l'instruction return() .

Des variables en arguments

Remarquez que l'on peut passer directement des variables en arguments, en écrivant leur nom. Ces variables seront remplacées par leur valeurs quand R exécutera la fonction :

vect1 = c(1,2,3)
vect2 = c(2,2,1)
addition(vect1,vect2)
 #affiche 3 4 4

Remarquons que c'est ce que nous faisions déjà à chaque que nous affichons un élément avec print(ma_variable) , ou que l'on demande le type d'une variable avec typeof(variable) .

Remarque : On parle aussi de "passer en paramétre" des valeurs ou des variables, au lieu de "passer en argument". Cela peut prêter à confusion sur la différence entre argument et paramétres. Il faut bien garder la différence en tête. Un paramétre d'une fonction est la variable interne créee par la fonction, et l'argument est la valeur qui est associé à cette variable lors de l'appelle de la fonction.

Stocker le résultat d'une fonction dans une variable :

Comme une fonction renvoit une valeur, on peut stocker son résultat dans une autre variable. Voyons cela avec un exemple :

vect1 = c(1,2,3)
vect2 = c(2,2,1)
res = addition(vect1,vect2) #on stock le retour de la fonction dans une variable

Cela est bien utile pour se souvenir de ce qu'une fonction à produit. Notons que ce fonctionnement est identique à ce que nous faisons quand nous stockons le résultat d'une expression dans une variable.

L'instruction return()

Une fonction en R renvoit toujours un résultat. En général, on utilise l'instruction return() pour préciser explicetment ce que la fonction doit renvoyer. Mais on peut également omettre cette instruction. Alors la fonction va renvoyer la derniére valeur manipulée par la fonction.

#Une fonction avec un return implicite :
doubler = function(nombre) {
     nombre*2 #la fonction va renvoyer le résultat de cette expression
}
print(doubler(3)) #affiche 6

Ici, nous déclarer une fonction doubler() qui prend un seul paramétre nombre et qui renvoit implictement le résultat de l'expression nombre*2 . Cette écriture sans instruction return est assez courante, mais nous vous déconseillons de l'utiliser. Il est plus lisible d'indiquer explicitement ce que renvoit la fonction. Et cela vous évitera d'oublier de préciser la variable a renvoyer, ce qui peut être problématique que vous voulez renvoyer autre chose que le dernier élement calculé !

Toute instruction qui se trouve aprés return() sera ignorée et ne sera jamais exécutée. Regardons avec un exemple :

#Une fonction avec un return implicite :
doubler = function(nombre) {
    return(nombre*2)
    print("bonjour")
}
print(doubler(3)) #affiche 6

On voit que la dernière instruction print("bonjour") n'est jamais exécutée, car elle est située après le return() .

Remarque : Toutes les fonctions renvoient quelque chose, même si elles peuvent faire autre chose à la fois. Ainsi la fonction print() affiche un objet dans la console, mais elle renvoit aussi toujours ce qu'on lui à passé en argument. Pour vous en convaincre, essayez le code suivant :

ma_variable = print("Bonjour")
ma_variable #affiche "Bonjour" car c'est la chaine passée en argument

Vous allez voir "bonjour" s'afficher deux fois dans la console : une première fois car c'est ce que fait naturellement la fonction print("Bonjour") en plus de renvoyer quelque chose, et une seconde fois car ce que contient la variable ma_variable .

Les paramétres d'une fonction

Revenons un peu plus en détail sur le fonctionnement des paramétres d'une fonction et le lien avec les arguments.

Passage par nom ou par ordre

Il existe deux façons de passer des arguments à une fonction : soit en les passant dans l'ordre, soit en les nomant. Nous avons pour le moment uniquement passé les arguments dans l'ordre des paramétres :

addition = function(x,y) {
    return(x+y)
}
addition(2,3) #on passe les arguments dans l'ordre

Dans ce cas, les arguments doivent être passés exactement dans l'ordre dans lesquels les paramétres sont déclarés dans la fonction. Le premier argument doit correspondre à la variable x , et le second à la variable y .

Il existe une autre façon de faire, qui consiste à indiquer explictement le nom de chaque paramétre, comme ceci :

addition(x = 2, y = 3)

Cette seconde façon de faire présente deux avantages majeurs :

  • Vous pouvez passer les arguments dans l'ordre que vous voulez, car le nom du paramétre auquel il est associé est explicitement indiqué. Ainsi écrire addition(y = 3, x = 2) donnera le même résultat. C'est trés pratique quand on appelle une fonction dont on l'utilise pas tous les paramétres.
  • Cela rend le code plus lisible. On voit directement le nom de chaque paramétre dans l'appelle de la fonction, ce qui permet de mieux comprendre à quel paramétre va correspondre chaque argument.

Paramétres par défaut

Il est possible de spécifier une valeur par défaut aux paramétres. Cette valeur sera utilisée si l'utilisateur oublie d'en donner une en argument. Il suffit pour cela de l'indiquer au moment de la création de la fonction, en précisant pour chaque paramétre sa valeur par défaut, si on souhaite lui en donner une. Ecrivons une fonction puissance() qui nous donne la puissance n d'un nombre x , et qui donne le carré du nombre par défaut :

puissance = function(x, n = 2) {
    return(x^n)
}
puissance(4) #affiche 16
puissance(4,3) #affiche 64

On donne ici au paramétre n la valeur par défaut n = 2 au moment de la déclaration de la fonction. Si l'utilsateur oublie de spécifier la valeur de n , c'est 2 qui sera alors utilisé.

Il est souvent intéressant de donner des paramétres par défauts aux fonctions, cela permet de prévoir un comportement "classique", que l'on peut modifier en donnant une valeur aux paramétres en questions différente de celle par défaut.

Les paramétres sont des variables internes

Quand on passe une variable en argument à une fonction, R va simplement en copier la valeur dans la fonction. Si on modifie le paramétre dans la fonction, seule la variable interne sera modifée, et jamais la variable d'origne passée en argument. Regardons un exemple :

x = 10
carre= function(x){
        x = x^2
        return(x)
    }
print(x) #affiche 10, la variable externe n'est pas modifé !

Ceci est une conséquence du fait que la fonction créer un scope (ou plutôt un environnement !) interne, et que le x de la fonction ne rencontre donc jamais le x de l'environnement global passé en paramétre.

Remarque : Attention à ne pas oublier de passer argument nécessaire ou à ne pas en donner un de trop à la fonction. Dans un cas comme dans l'autre, R refusera d'éxécuter la fonction.

La notion de scope

Une notion fondementale quand on parle de fonctions et de variables est la notion de scope , ou de portée des variables. Le scope d'une variable est la portée dans laquelle est elle accessible, c'est à dire où on peut manipuler cette variable. Une variable ne peux jamais être accessible depuis un scope de portée supérieure. Une fonction créer son propre scope . Ainsi, les variables déclarées à l'intérieur d'une fonction ne sont accessibles que pour le code qui se trouve aussi dans cette fonction.

Si cela peut sembler un peu compliqué, regardons avec un exemple :

ma_fonction = function() {
    a = 10
    print(a)
}
ma_fonction() #affiche 10
print(a) # "Error in print(a) : object 'a' not found"

Si on exécute ce code, on remarque que l'appelle ma_fonction() va afficher 10 dans la console, mais que le print(a) de la dernière ligne affichera lui une erreur : Error in print(a) : object 'a' not found . La variable a n'existe que dans le nouveau scope crée par la fonction ma_fonction() et n'est pas accessible en dehors. Comme l'instruction print(a) de la fin du programme se trouve dans le scope global, elle ne peut accéder à la variable a , ce qui produit une erreur.

Le scope le plus proche l'emporte

Cette notion de scope est bien pratique : comme une fonction créer son propre scope à chaque fois, on peut donner à une variable dans la fonction le même nom qu'une variable extérieure, sans que celle-ci ne soit modifée et sans créer de conflit. Plusieurs variables avec le même nom peuvent alors cohabiter dans des scopes différents.

Quand plusieurs variables avec le même nom vivent dans des scopes différents, R va toujours choisir la variable dans le scope le plus proche. Regardons cet exemple :

a = 1
ma_fonction = function() {
    print(a)
    a = 10
    print(a)
}
ma_fonction() #affiche 1, puis 10
print(a) #affiche 1

Dans ce code, le premier print(a) qui se trouve dans la fonction ma_fonction() fait référence à la variable a dans le scope global, c'est à dire a = 1 . En effet, c'est la seule variable a qui existe pour le moment. On peut ainsi remarque que une variable est toujours accessible dans les scopes inférieurs.

Mais à partir du moment où l'on redéfinit une variable a = 10 dans le scope de la fonction ma_fonction() , alors deux variables a existent : une dans le scope global qui vaut 1 , et une nouvelle dans le scope de la fonction qui vaut 10 .Ainsi la derniére instruction de la fonction, print(a) affiche 10 , car elle fait référence maintenant a la variable a la plus proche, qui est celle du scope de la fonction et faut 10 .

Comme les deux variables vivent dans des scopes différents le a du scope global (celui de la première ligne) n'est lui pas modifé par la fonction. On peut l'afficher avec print(a) de la dernière instruction, et il a bien gardé sa valeur de 1 .

Scope et environnement

Si vous vous souvenez bien, au chapitre sur les variables nous avions parlé d'environnement, en disant que c'était là que vivent les variables. Quelle différence existe-il entre le scope et l'environnement ? La différence est la suivante : le scope représente la portée d'une variable , c'est à dire qu'il défini l'ensemble des "endroits" dans lesquels cette variable est acessible. Alors que l'environnement lui est une collection de variables et objets qui vivent à un même niveau direct.

Regardons le code suivant pour bien comprendre la différence :

a = 1
ma_fonction = function() {
    b = function() { #On déclare une autre fonction qui vit dans la premiére 
        print(a)
    }
}

On peut dire que l'environnement global comprend la variable a et la fonction ma_fonction , car les deux "vivent" au même niveau. La fonction b ne fait pas parti de l'environnement global, car elle ne vit pas directement au même niveau que les deux autres. Elle fait partie de l'environnement crée par la fonction ma_fonction .

Si on regarde le scope de la variable a , c'est à la fois l'environnement global, la fonction ma_fonction , et la fonction b . En effet, ces trois objets peuvent accéder à la variable a .

On peut représenter tout ceci sur un schéma qui représente l'imbrication des différents environnements et éléments. Sur le premier dessin, on peut voir en gris les éléments contenus dans l'environement global, qui est l'environnement de la variable a :

On voit que qu'il ne contient que deux objets, la variable a et la fonction ma_function . Voici sur un autre schéma le scope de la variable a , colorié en rose :

On voit bien que cette fois la variable a est accessible partout dans notre programme. Son scope (portée) est donc bien différent de son environnement(là où elle vit).

Cela dit, en pratique, on utilise souvent les deux termes de façon synonyme, malgré la différence réelle qui existe entre eux !

Un exemple courant consiste à parler de scope ou de scope interne d'une fonction pour en designer l'environnement qu'elle créer, aussi bien que pour parler de l'ensemble des éléments dans lesquels elle est accessible. Aussi habituez vous à utiliser ces deux termes de façon quasi-équvalente. En réalité, la plupart des programmeurs avancés ne sauraient même pas vous expliquer la différence entre les deux, tellement ils sont utilisés de façon similaire. D'ailleurs vous avez du remarqué que quand nous avons présenté le scope, nous avons largement abusé du sens stricte de ce terme !

Fonctions pures et fonctions impures

Une notion importante à connaitre en programmation est la notion de fonction pure et de fonction impure. Une fonction pure est une fonction que n'a aucun impact en dehors du corps de la fonction et dont le résultat ne dépend de rien d'autre que la valeur des arguments passés à la fonction. A l'inverse, une fonction impure dépend du contexte extérieur de la fonction, ou le modife.

Voyons d'abord comment une fonction pure se présente :

addition = function(x,y) {
    return(resultat = x + y)
}

Cettte fonction est pure car elle n'a aucun effet extérieur, et ce qu'elle va renvoyer dépend uniquement des paramétres x et y . Si nous donnons les deux même arguments à chaque fois, alors la fonction va renvoyer toujours le même résultat, quoi qu'il se passe dans le reste de votre programme.

On dit qu'une fonction pure est sans effet de bord, car elle n'a aucun effet sur le reste du programme.

Les fonctions impures

Regardons maintenant la différence avec une fonction impure.

total = 0 
somme_n_entiers = function(n) {
    for(i in 1:n) {
        total = total + i
    }
    return(total) 
}
some_100 = somme_n_entiers(100)
some_200 = somme_n_entiers(200)
print(some_100) #5050
print(some_200) #20100

La fonction somme_n_entiers() est impure. Son résultat dépend en effet de la variable total , qui est extérieur à la fonction. Ainsi si on modifie la valeur de total = 0 pour écrire total = 10 , alors somme_n_entiers(100) ne renvera plus la même valeur qu'avant ! Alors que les arguments sont les mêmes (100 ), le résultat renvoyé est différent, car la fonction dépend du contexte extérieur.

On peut remarquer que notre fonction somme_n_entiers est "doublement" impure : non seulement elle dépend d'une variable extérieur à la fonction, mais en plus elle modifie également cette variable. On parle alors d'effet de bord car la fonction à un effet en dehors de ce qui se passe dans son propre corps.

Transformer une fonction impure en fonction pure

Il est souvent facile de transformer une fonction impure en fonction pure. Il suffit pour cela de la ré-écrire de façon à ce que toutes l'information utile au fonctionnement de la fonction sont compris dedans, tout en évitant de modifer des variables extérieurs. On peut facilement rendre la fonction somme_n_entiers() pure en inculant la variable total à l'intérieur :

somme_n_entiers = function(n) {
    total = 0
    for(i in 1:n) {
        total = total + i
    }
    return(total) 
}

Notre fonction est maintenant pure, son résultat sera toujours identique pour deux valeurs de n identiques, quel que soit les modifications que l'on puisse faire sur le reste du programme.

Pourquoi écrire des fonctions pures ?

Une fonction pure est bien plus sure d'utilisation : vous êtes sur par définition que jamais elle ne provoquera de probléme ailleurs dans votre code en modifiant une variable sans que vous ayez fait attention. De même, son résultat de dépendra jamais de ce qui se passe ailleurs, mais uniquement des paramétres. Ecrire des fonctions pures est donc une façon d'écrire du code plus robuste aux erreurs.

Une fonction pure est aussi plus facile à comprendre : tous ce qui est utile est contenu dans les paramétres et dans le corps de la fonction. Pas besoin par exemple d'aller chercher à quoi correspond la variable total ailleurs dans le programme, et de vérifier qu'on a bien le droit de la modifier.

Nous vous conseillons d'écrire autant que vous pouvez des fonctions pures. Leur résultat ne doit jamais déprendre d'autre chose que des paramétres, et elles ne doivent avoir aucun impact sur les autres variables en dehors du corps de la fonction.

Parfois il est néanmoins impossible d'utiliser une fonction pure. Il arrive même que l'on cherche volontaire à avoir un effet de bord. Par exemple la fonction print() est impure car elle affiche quelque chose dans la console, ce qui est un effet de bord. Mais c'est justement ce qu'on attend d'une telle fonction ! Si vous pensez que vous avez vraiment une bonne raison d'utiliser une fonction impure, n'hésitez donc pas à le faire. Essayez simplement d'écrire des fonctions pures chaque fois que cela est possible.

Les fonctions sont des données comme les autres

Pour finir ce chapitre d'introduction sur les fonctions, voyons plus en détail ce qu'est réellement une fonction. Que ce passe-il en détail quand nous déclarons une fonction ?

addition = function(nombre1, nombre2) {
    return(nombre1 + nombre2)
}

En réalité, la fonction en tant que telle est simplement le bout de code suivant :

function(nombre1, nombre2) {
    return(nombre1 + nombre2)
}

Mais si nous écrivons ce bout de code directement dans la console, il ne va "rien" se passer : la console va simplement nous afficher notre fonction, comme elle le fait si on lui écrit une autre donnée (comme un vecteur c(2,3) ). Pour éviter cela, on stock la fonction dans une variable. Ici dans la variable addition . Une fonction est en réalité une donnée comme les autres.

addition n'est pas une fonction en soit, mais une variable qui contient une fonction. Quand on parle de la fonction addition() , on parle en réalité de la fonction contenue dans la variable addition .

Appeller une fonction non stockée dans une variable

Par ce qu'une fonction est une donnée comme les autres, écrire dans la console le nom de la variable qui la contient ne va appeler la fonction, mais va juste afficher le contenu de la variable, soit la fonction en elle même. Comme R afficherai le contenu de n'importe quelle autre variable.

Pour appeler une fonction, il faut plutôt utiliser () juste aprés le nom de la variable la contenant :

addition(2,3) #on appelle la fonction contenue dans la variable addition

Mais on peut aussi utiliser cette syntaxe directement depuis la fonction elle même ! Il suffit pour cela d'envelopper le code de la fonction dans des () , comme ceci :

(function(nombre1, nombre2) {
    return(nombre1 + nombre2)
})(2,3) 
#affiche 5

Ici, on a directement écrit une fonction, que l'on utilise instantanément, sans même la stocker dans une variable ! Bien entendu cette fonction est à usage unique, vu qu'elle n'est enregistrée nulle part. Une fois utilisée, R ne s'en souviendra plus. Exactement comme si on lui demande d'effecter 2 + 3 dans la console. R évalue l'expression, puis l'oublie.

Les fonctions sont des expressions

En réalité, une fonction est très proche d'une expression : c'est quelque chose qui produit une valeur (celle renvoyée par la fonction). Simplement a la différence d'une expression "normale", doit être évaluée explictement en ajoutant () , et en précisant entre ces parenthéses les arguments pour les paramétres. Une expression "normale" est toujours remplacée par sa valeur automatiquement par R. A cette petite différence prêt, une fonction se comporte néanmoins exactement comme une expression ! Voir les fonctions comme des expressions qui produisent des valeurs quand elles sont évaluées explictement avec des () contenant les arguments de la fonction est une vision très puissante, qui permet de mieux saisir la nature profonde des fonctions.

Le type des fonctions

Si les fonctions sont des données comme les autres, elles doivent bien avoir un type non ? Regardons cela en utilisant notre fonction typeof() que nous connaissons bien :

addition = function(nombre1, nombre2) {
    return(nombre1 + nombre2)
}
typeof(addition) #affiche Closure

Le type d'une fonction est closure , ce qui veut dire "fermeture" en anglais. Dans le chapitre avancé sur les fonctions, nous expliquerons d'où vient ce terme. On peut néanmoins le voir comme étant synonyme du terme fonction.

Remarquez à propos du type que votre onglet environnement lui affiche un type différent : il affiche function et non closure :

Ceci est dû comme nous l'avons vu dans les premiers chapitres à une petite erreur de R Studio : Ce qui est affiché dans l'onglet environment ne correspond pas pas en réalité au typed'un objet, mais à une autre propriété de l'objet, qui est sa class . Si vous écrivez class(addition) , la console devrait vous afficher function . Nous discuterons en détail de la différence entre la class et le type d'un objet dans la partie avancée de ce cours.

A retenir :

  • On peut utiliser des fonctions pour regrouper en un endroit une suite d'instructions pour les utiliser à plusieurs endroit dans notre programme. On écrit une fonction comme ceci : ma_fonction = function(x, y) {#instructions } .
  • Une fonction peut prendre entre 0 et une infinité de paramétres, qui doivent être nommés.
  • On appelle une fonction en écrivant le nom de la variable qui la contient, suivit de () . On passe les différents arguments de la fonction entre les parenthèses. Chaque paramétre de la fonction prendra comme valeur les arguments passés.
  • Une fonction renvois toujours le dernier élément qu'elle manipule. Il est conseillé de définir explictement ce que l'on renvoit avec l'instruction return() .
  • Le scope d'une variable est l'ensemble des endroits où elle est acessible. Toute variable créee dans une fonction n'est accessible que dans cette fonction. Une variable d'un environnement supérieur est toujours acessible. Une fonction à ainsi toujours accés aux variables de l'environnement global (ou scope global par abus de langage).
  • Si deux variables dans deux scopes différents ont le même nom, c'est celle du scope le plus proche qui est utilisée.
  • On peut passer les arguments par ordre de déclaration des paramétre, ou alors spécifier devant chaque argument le nom du paramétre associé.
  • On peut préciser une valeur par défaut aux paramétres lors de la déclaration de la fonction simplement en leur affectant une valeur. Il faut passer précisement le nombre d'argument égal au nombre de paramétres qui n'ont pas de valeur par défaut pour qu'une fonction soit appellée correctement. Si il y a trop ou pas assez d'argument, R renvoit une erreur.
  • Une fonction pure est une fonction qui n'a aucun effet sur l'environnement, ni ne dépend d'une variable externe. Sa valeur est toujours uniquement dépendente de ses arguments. Une fonction impure est une fonction qui à un effet sur l'environnement ou qui dépend d'une variable externe. On parle aussi d'effet de bord.
  • Il est conseillé d'écrire des fonctions pures, car elles sont plus lisibles et moins sujettes aux bugs car indépendantes du reste du programme.
  • Les fonctions sont en réalité des données comme les autres, que l'on stock dans des variables. Leur type de donnée est le type closure .

Exercices :

Exercice 1 :

Ecrivez une fonction minimum qui prend en paramétre deux nombres, et qui donne le nombre le plus petit des deux. Par exemple :

minimum(5,2) #doit afficher 2
minimum(-5,2) #doit afficher -5

Exercice 2 :

Supposons que vous travailliez comme analyse financier pour une banque. On vous demande de suivre l'action Apple et de calculer sa rentabilité chaque jour. Si le premier jour cette action vaut 100$ et qu'elle en vaut 110$ le lendemain, sa rentabilité sur un jour est de 10%. Ecrivez une fonction qui prend en entrée un vecteur de prix c(100,110,108,105,107) et qui renvois en retour le vecteur des rentabilités.

Rappel : La rentabilité entre deux prix est donnée par la formule : rentabilite = (prix2 - prix1) / prix1 .

Exercice 3 :

Existe-il une différence entre ces deux fonctions ? Pourquoi ?

#Cette fonction vérfie si vous êtes majeur, et renvois TRUE si oui, FALSE sinon
check_age = function(age) {
    if(age >= 18) {
        return(TRUE)
    } else {
        return(FALSE)
    }
}


check_age2 = function(age) {
    if(age >= 18) {
        return(TRUE)
    } 
    return(FALSE)    
}

Exercice 4:

Cette fonction fois_dix()est-elle une fonction pure ?

a = 10
fois_dix = function(x) {
    return (x*a)
}

Réponses corrigées :

A venir.

results matching ""

    No results matching ""