# Effets algébriques en OCaml 5

Florian Angeletti
Cambium/Inriasoft

# Effets algébriques

Une nouveauté expérimentale dans OCaml 5:

## Des exceptions résumables

• Lire ou écrire un fichier
• Générer une valeur aléatoire
• Lancer une action en en tâche de fond
• co-routines
• yield en python
``````
def integers():
i = 0
while True:
i += 1
yield i
``````
``````
g = integers()
for i in range(10):
print (next(g))
``````
``````
0
1
2
3
4
5
6
7
8
9
``````
``````
my_gen =
map(
(lambda i: yield i),
[10,20,30,40])
)
``````
``````
def do_yield(acc,i):
yield i
import functools
my_gen = functools.reduce(
do_yield,
[10,20,30,40]
0)
print (next(my_gen))
``````
``````
40
``````

# Retourner vers le passé

``````g = integers()
print (next(g))
print (prev(g))``````

# Apprendre à attendre

``````def slow_prims():
prims = [];
i = 1
while True:
for j in range(10):
i+=1
if all(i % x != 0 for x in prims):
prims.append(i)
yield i
break
else:
wait ()``````
1. Définir un effet `Yield`
``````type 'a Effect.t += Yield: int -> unit Effect.t
let yield x = Effect.perform (Yield x)
``````
2. Écrire des générateurs
``````let integers () =
let i = ref 0 in
while true do
i := !i + 1;
yield !i
done; 0
``````
3. ???
4. Utiliser le générateur
`````` let g = init integers
let () =
for _ = 0 to 100 do
Format.printf "g=%d@." (next g)
done
``````
``````let init f = ref (Effect.Shallow.fiber f)

let yield_handler (r:(unit,int) Effect.Shallow.continuation ref) =
let effc (type a) (eff:a Effect.t) = match eff with
| Yield x -> Some (fun (cont: (a,_) Effect.Shallow.continuation)  ->
r:= cont;
x
)
| _ -> None
in
{
Effect.Shallow.retc = (fun _ -> raise (Invalid_argument "Finite generator"));
exnc = raise;
effc;
}

let next f = Effect.Shallow.continue_with !f () (yield_handler f)
``````
``````

def slow_prims():
prims = [];
i = 1
while True:
for j in range(10):
i+=1
if all(i % x != 0 for x in prims):
prims.append(i)
yield i
break
else:
wait ()
``````
``````type _ Effect.t += Wait: unit Effect.t
let wait () = Effect.perform Wait

let slow_prims () =
let primes = ref [] in
let i = ref 1 in
while true do
match for j = 1 to 10 do
incr i;
if List.for_all (fun p -> !i mod p <> 0) !primes then
(primes := !i :: !primes;
yield !i;
raise Exit)
done with exception Exit -> ()
| () -> wait ()
done; 0

``````
``````let yield_or_wait (r:(unit,int) Effect.Shallow.continuation ref) =
let effc (type a) (eff:a Effect.t) = match eff with
| Yield x -> Some (fun (cont: (a,_) Effect.Shallow.continuation)  ->
r:= cont;
Some x
)
| Wait -> Some (fun (cont: (a,_) Effect.Shallow.continuation)  ->
r:= cont;
None
)
| _ -> None
in
{
Effect.Shallow.retc = (fun _ -> raise (Invalid_argument "Finite generator"));
exnc = raise;
effc;
}

let try_next f = Effect.Shallow.continue_with !f () (yield_or_wait f)
``````
``````let () =
let primes = init slow_prims in
for _ = 1 to 100 do
match try_next primes with
| Some prime -> Format.printf "%d@." prime
| None -> Format.printf "Waiting on next prime@."
done
``````
``````let () =
let gen = init integers in
for _ = 1 to 100 do
match try_next gen with
| Some prime -> Format.printf "%d@." prime
| None -> Format.printf "Waiting on next prime@."
done
``````
``````type dir = Next | Previous
type _ Effect.t += Dir_yield: int -> dir Effect.t

let directional_yield x = Effect.perform (Dir_yield x)

let rec integers current dir =
let current = match dir with
| Next -> current + 1
| Previous -> current - 1
in
let next_dir = directional_yield current in
integers current next_dir
``````
``````let () =
let generator = init (integers 0) in
for _=1 to 100 do
Format.printf "%d@."
(if Random.bool () then next generator else prev generator)
done
``````
``````let dir_yield (r:(dir,int) Effect.Shallow.continuation ref) =
let effc (type a) (eff:a Effect.t) = match eff with
| Dir_yield x -> Some (fun (cont: (a,_) Effect.Shallow.continuation)  ->
r:= cont;
x
)
| _ -> None
in
{
Effect.Shallow.retc = (fun _ -> raise (Invalid_argument "Finite generator"));
exnc = raise;
effc;
}

let step f dir = Effect.Shallow.continue_with !f dir (dir_yield f)
let next f = step f Next
let prev f = step f Previous
``````

## Effets algébriques

• Des exceptions résumables
• Découple
• le code qui effectue des effets
• l'implémentation des effets
• Sans passer par des monades