Introduction

Rappel du cours 1 : fonctions (fun, let, let rec), récursion, tail recursion, récurseur sur ℕ, listes (::, []), recurse_list (fold_right), map, filter.

Ce cours : le mot-clé type, les types algébriques, le pattern matching exhaustif, l'AST, la compilation en bytecode.

« La programmation fonctionnelle, c'est comme la cuisine : si vous ne comprenez pas la différence entre une carotte et une carotte coupée en dés, vous allez avoir du mal à suivre la recette. Les types, c'est pareil. »

Les trois formes de fonctions (rappel)

Exercice

Écrivez une fonction apply_twice f x qui applique f deux fois : apply_twice (fun x -> x * x) 2 = 16.

Fonctions : variations et curryfication

let add a b = a + b
let add = fun a b -> a + b
let add = fun a -> fun b -> a + b

Application partielle :

let add5 = add 5   (* val add5 : int -> int *)
(* add5 3 -> 8 *)

Pipe |> :

let ( |> ) x f = f x
let r = [1;2;3;4;5;6]
  |> List.filter (fun x -> x mod 2 = 0)
  |> List.map (fun x -> x * x)

Les types algébriques

Principe : on décrit les formes possibles d'une valeur.

Entiers de Peano :

type nat = Zero | Succ of nat

let trois = Succ (Succ (Succ Zero))

let rec to_int n = match n with
  | Zero -> 0
  | Succ n -> 1 + to_int n

Types sommes et produits

Type somme — OU logique (|) :

type couleur = Rouge | Vert | Bleu
type option = Rien | Chose of int

Type produit — ET logique :

type paire = int * string             (* anonyme *)
type point = { x : int; y : int }    (* record *)

Combinaison :

type forme = Cercle of float | Rect of float * float
type image = forme list

Les listes (version maison)

type 'a lst = Nil | Cons of 'a * 'a lst

let rec map f l = match l with
  | Nil -> Nil
  | Cons (x, xs) -> Cons (f x, map f xs)

« Le mot Cons vient de construct, mais les étudiants disent Constantine parce que ça reste dans la tête. »

Les arbres binaires

type 'a tree = Leaf | Node of 'a * 'a tree * 'a tree

let rec hauteur t = match t with
  | Leaf -> 0
  | Node (_, g, d) -> 1 + max (hauteur g) (hauteur d)

« Les arbres, c'est comme les listes, mais avec deux enfants. Quand vos parents ont un deuxième enfant, la récursion devient plus intéressante. »

AST — Votre programme devient une data structure

type expr =
  | Int of int
  | Add of expr * expr
  | Sub of expr * expr
  | Mul of expr * expr

let rec eval e = match e with
  | Int n -> n
  | Add (a,b) -> eval a + eval b
  | Sub (a,b) -> eval a - eval b
  | Mul (a,b) -> eval a * eval b

Dérivation formelle

Les règles de dérivation sont des transformations d'AST :

let rec derive e = match e with
  | Int _ -> Int 0
  | Add (a,b) -> Add (derive a, derive b)
  | Mul (a,b) ->
    Add (Mul (derive a, b), Mul (a, derive b))

(a × b)' = a' × b + a × b' écrite en OCaml.

Bytecode et CPU virtuel

type instr = PUSH of int | ADD | SUB | MUL

let rec compile e = match e with
  | Int n -> [PUSH n]
  | Add (a,b) -> compile a @ compile b @ [ADD]
  | Sub (a,b) -> compile a @ compile b @ [SUB]
  | Mul (a,b) -> compile a @ compile b @ [MUL]

compile a @ compile b @ [ADD] = « calcule a, calcule b, additionne ».

Du type au processeur : Type → Pattern → Fonctions → Bytecode → CPU

Prochain cours

Cours 3 : les monades. On va généraliser le pattern bind/return qu'on a entrevu avec option.