Mais plutôt que de "détourner" Python pour faire de la programmation fonctionnelle, ne serait-il pas plus simple d'utiliser un langage fait pour cela ?
Vous avez déjà eu un aperçu de Lisp, qui est un langage fonctionnel.
Le langage Haskel est exclusivement fonctionnel, il interdit l'affectation des variables etc...et est donc très difficile de coder ainsi.
Le langage Ocaml fait partie de la famille des langages ml
, c'est aussi celui qui a été choisi pour l'enseignement de l'informatique en CPGE.
Il est "orienté programmation fonctionnelle" mais autorise quelques incartades au paradigme.
Nous allons (une fois n'est pas coutume...) découvrir un nouveau langage de programmation et tenter de programmer quelques fonctions simples en respectant le paradigme fonctionnel
(autant que possible).
Cela va être perturbant, car nous allons sortir de nos habitudes, à la fois pour la syntaxe et pour la réflexion algorithmique.
OCaml (pour Objective Caml) est un langage de programmation fonctionnel de la famille ML
(pour MetaLanguage ; Standard ML est l’autre langage fonctionnel le plus utilisé avec F#), dont
les racines sont tirées de Lisp (1958).
Il est développé en France par l’INRIA (Institut National de Recherche en Informatique et en Automatique).
OCaml est installé sur les PC du lycée; si vous lancez OCaml dans le menu, vous obtenez une fenêtre de shell ( = interpréteur ) comme ci-dessous :
Le prompt est représenté par un #
, et non >>
comme en Python.
Nous pouvons donc déjà tester ici quelques "commandes" OCaml.
Tapez le code ci-dessous :
let f x = 2*x + 1;;
Même si vous ne connaissez pas ce langage, votre culture informatique vous permet de repérer que nous somme en train de définir une fonction.
Si vous validez cette ligne, des informations apparaissent, à vous de les décoder...
Nous allons maintenant utiliser cette fonction. Pour cela tapez puis validez :
f 3;;
Le résultat proposé semble assez clair...
On peut remarquer qu'ici les ;;
permettent d'envoyer le code à l'exécution. Le résultat est affiché (effets de bord !) et le type de l’expression évaluée est affiché.
Pour quitter la console, on peut au choix taper #exit 0;;
ou #quit;;
, le dièse fait ici partie de la commande (Ctrl D fonctionne également).
OCaml est un langage qu'il est possible de compiler, c'est un de ses grands intérêts.
Pour travailler avec un script, nous n'allons pas mettre en place un environnement de développement spécifique, nous allons travailler à l'ancienne.
Pour cela vous aurez besoin de :
Pour plus de clarté nous allons travailler sur un exemple :
Voici ce que vous devez faire pour exécuter un script :
let x = 2.0
let y =
let x2 = x *. x in
let x4 = x2 *. x2 in
x4 *. x4
let () =
Printf.printf "x = %f ; y = %f\n" x y
Puis enregistrer le fichier sous le nom test1.ml
.
ocamlc -o premiertest test1.ml
( ainsi OCaml va transformer votre script test1.ml
en un fichier exécutable premiertest
).
./premiertest
En cas d'erreur d'exécution du script, un message approprié apparaîtra dans le shell système :
Les éditeurs de cette page sont paramétrés pour interpréter directement du code OCaml :
Nous allons d'abord essayer de découvrir la base de la syntaxe en OCaml, en utilisant la ligne de commande.
Schématiquement, un programme OCaml est une suite d’instructions globales let
dont le rôle est de lier un identifiant à une valeur.
Quand on écrit :
let x = 3 ;;
→ on lie la valeur 3 à l'identifiant x. On ne pourra (devra) plus modifier la valeur de x ensuite.
On peut traduire let
par "soit" comme on dirait en mathématiques "soit x égale 3".
Les noms de valeurs doivent commencer par une lettre minuscule ou par _.
Ils peuvent contenir des chiffres, des majuscules, l’underscore _ et l’apostrophe (ce qui permet des noms comme x' ou x'' ).
Les opérateurs classiques +, -, *, / ne sont pas les mêmes pour les entiers et les flottants :
+
, -
, *
, /
pour les entiers+.
, -.
, *.
, /.
pour les flottantsVous pouvez ainsi tester :
2 + 3;;
puis :
2.2 + 3.3;;
et enfin :
2.2 +. 3.3;;
Les opérateurs booléens s'écrivent &
ou &&
, or
ou ||
, not
.
On préfère généralement utiliser &&
et ||
pour ne pas utiliser and
comme opérateur booléen.
and
n'est pas un opérateur booléen en OCaml.
Il permet de définir des constantes locales de même niveau simultanément.
let x = 1 and y = 2 ;;
Pour ce qui est des types, OCaml dispose de tous les types classiques :
int
)float
)bool
)char
), délimité par des '
string
), délimité par des "
()
qui signifie rien, c'est le None
).Il existe aussi des types construits :
tuple
list
array
Mais nous ne les utiliserons pas dans cette petite initiation à OCaml.
Pour appliquer tout cela, deux petits exercices :
Le nombre pi n'est pas implémenté dans OCaml; pour l'utiliser on se servira de la fonction tangente.
En math, vous savez que tan(π /4) = 1 . On utilisera donc la valeur arctan(1) qui s'écrit en Ocaml atan 1.
Comme vous l'avez vu, il est possible de lier une valeur et un nom. La liaison classique est alors globale pour tout le programme ou la session de terminal.
Mais il est aussi possible de déclarer un nom de façon locale, pour simplifier l'écriture d'un calcul par exemple.
La structure de la liaison est alors la suivante :
let ..... in .....
La portée de la liaison locale se limite à la série d'instructions suivant le in
.
Pour mieux comprendre ce concept, il faut bien sur l'expérimenter...
Par exemple :
let x = 3 in x + 1;;
→ liera x avec la valeur 4.
On peut vérifier que la portée de la variable locale y est limitée dans l'exemple suivant :
Essayez de prévoir la valeur renvoyée par les liaisons suivantes :
(* exemple 1*)
let x = 3 in x * x;;
(* exemple 2*)
let x = 7;;
let y = 5 in x * y;;
(* exemple 3*)
let x = 3 in let x = x + 1 in x + 3;;
(* exemple 4*)
let a=
let pi = 4. *. atan 1. in
cos(pi /.3);;
(* exemple 5*)
let a,b = true, false in a && b;;
Avec ces quelques notions, nous commençons à pouvoir coder en OCaml. Mais si nous utilisons le paradigme fonctionnel, il serait cohérent de savoir coder une fonction.
La définition de fonction est assez simple en Ocaml :
let
let nomDeFonction paramètre(s) = expression
Par exemple :
let carreEntier x = x * x ;;
L'appel de fonction se fait également sans parenthèse:
carreEntier 3 ;;
Une fonction peut également avoir plusieurs variables :
let somme a b = a + b ;;
Le résultats renvoyé par OCaml est alors :
val somme : int -> int -> int = ‹fun›
→ on retrouve donc bien la trace et les types associés aux paramètres et à la fonction elle-même. On peut éventuellement remarquer que l’enchaînement des types est étonnant.
En fait, OCaml ne gère que des fonctions d'une seule variable et travaille avec des fonction composées, ici f(a(b))
.
Contrairement à Python, pas de return
en OCaml : la fonction renvoie la dernière expression évaluée (comme Lisp...)
On peut également coder des fonctions sans paramètre, notamment pour isoler les effets de bords (affichages, saisie) en dehors du code principal, et garder ainsi autant que possible les avantages de la programmation fonctionnelle :
let affiche () = print_string "ceci est un effet de bord";;
→ on remarque ici l’apparition de parenthèses : elle ne signifient pas qu'il n'y a pas de paramètre entre ces parenthèses.
()
est bien ici le seul objet de type unit
(il correspond à None
en python).
On précise donc que le paramètre de la fonction est None
: elle ne renvoie rien.
Pour appeler la fonction, il sera également nécessaire de préciser ce paramètre :
# affiche ();;
ceci est un effet de bord
- : unit = ()
Bon, tout cela est bien simple, vu votre niveau en programmation, vous aimeriez bien aller un peu plus loin...
Nous allons donc nous attaquer aux fonction récursives. Mais avant cela, vous vous rappelez qu'une fonction récursive, c'est (si on simplifie un peu...):
→ il faut donc nécessairement pouvoir traiter des conditions.
La syntaxe du traitement conditionnel en OCaml est assez simple :
if ... then ... else...
Comme dans cette fonction :
Nous pouvons constater ici que cette fonction, par l'affichage de chaînes de caractères, entraîne des effets de bord.
Normalement, tous les effets de bords devraient être isolés dans des fonctions "à part".
Les fonction récursives en OCaml sont déclarées différemment avec le mot clef rec
:
let rec frecurs x =
...
Le plus simple encore une fois est de consulter un exemple :
On reconnaît ici la fonction factorielle. Les sauts de ligne ne sont pas obligatoires mais permettent "d'aérer" le code.
fact 5;;
print_int(fact 5);
print_newline ();;
Il y aurait encore beaucoup de choses à dire pour égaler en OCaml vos connaissances en Python.
Mais cela va suffire pour réaliser quelques exercices basiques.
abs
qui renvoie la valeur absolue d'un réel.max
qui prend 4 paramètres a, b, c, d et qui renvoie le couple de valeur correspondant à la fraction a/b ou c/d la plus grande.racine
qui prend 3 paramètres a, b, c et qui renvoie les solutions réelles de l'équation a.x²+b.x+x=0.