Cours alternatif d’OCaml

Logo OCaml
VII — Ordre supérieur

Ordre supérieur

Depuis le début de ce cours, on manipule des fonctions. On va maintenant passer au niveau au-dessus avec l’ordre supérieur, en manipulant des fonctions de fonctions. Ça peut faire peur, ou sembler incompréhensible, mais ne vous inquiétez pas, il n’y a rien de très compliqué en réalité.

Un langage est dit d’ordre supérieur si on peut utiliser des fonctions comme arguments d’autres fonctions et si une fonction peut en renvoyer une autre. Et c’est le cas d’OCaml !

Prenons un exemple simple : la composition d’une fonction avec elle-même Petit rappel : le type d’une fonction qui prend des a, b, et c comme arguments et renvoie un d s’écrit a -> b -> c -> d. Admettons qu’on veuille composer une fonction de type int -> int. On peut alors écrire :

let composition (f : int -> int) (x : int) : int = f (f x)

composition est une fonction d’ordre supérieur : elle prend une autre fonction comme premier argument. On peut l’utiliser de cette façon par exemple :

let ajoute_deux (x : int) : int = x + 2

composition ajoute_deux 4 (* ajoute_deux (ajoute_deux 4) = 2 + 2 + 4 = 8 *)

Attention, ici 4 n’est pas l’argument de ajoute_deux, mais bien celui de composition. Pour vous aider à comprendre l’exemple ci-dessus, voici l’équivalent en Python :

def composition(f):
  return f(f(x))

def ajoute_deux(x):
  return x + 2

composition(ajoute_deux, 4) # On appelle pas ajoute_deux, on donne juste son nom

L’ordre supérieur devient assez intéressant quand on manipule des listes : on peut appliquer une fonction à tous les éléments d’une liste par exemple. Ou filtrer une liste en se basant sur une fonction donnée.

Mais comme il a été dit plus haut, l’ordre supérieur permet aussi de renvoyer des fonctions. Voici un exemple :

let bonjour (nom : string) : string = "Bonjour " ^ nom
let hello (nom : string) : string = "Hello " ^ nom
(* bonjour et hello sont de types string -> string *)

(* Saluer renvoie une fonction de type string -> string *)
let saluer (langue : string) : (string -> string) =
  match langue with
  | "francais" -> bonjour (* On renvoie juste la fonction, on ne l’appelle pas avec des arguments *)
  | _ -> hello

let saluer_en_anglais = saluer "anglais" (* La fonction hello sera renvoyée *)
saluer_en_anglais "Jeanne" (* donne "Hello Jeanne" *)

Ici aussi, je vous mets l’équivalent en Python pour vous aider à comprendre :

def bonjour(nom):
  return "Bonjour " + nom

def hello(nom):
  return "Hello " + nom

def saluer(langue):
  if langue == "francais":
    return bonjour # On retourne bien la fonction, on ne l’appelle pas
  else:
    return hello

saluer_en_anglais = saluer("anglais")
saluer_en_anglais("Jeanne")

Toujours plus de fun

Pour créer des fonctions « à la volée », c’est-à-dire sans avoir à leur donner un nom en avance, on peut utiliser le mot-clé fun qui crée une fonction anonyme, sans nom. On écrit juste fun, le nom des arguments de la fonction, puis une flèche (->) et le corps de la fonction. Voici le même exemple qu’au-dessus, sauf que cette fois, on ne définit pas bonjour et hello en avance :

let saluer langue =
  match langue with
  | "francais" -> (fun nom -> "Bonjour " ^ nom)
  | _ -> (fun nom -> "Hello " ^ nom)

Peut-être que tout n’est pas encore très clair pour vous, mais si besoin la prochaine page et les exercices à la fin du chapitre vous aideront.