À vrai dire j'ai du mal à te suivre, tu sais sans doute mieux que moi ce dont tu parles, on peut sans doute faire ce que tu dis, mais ce n'est pas la motivation que j'y avais vue au départ.Envoyé par bluestorm
Ton bling bling m'a l'air d'une nature passablement impérative.
J'ai l'impression que tu voudrais te servir des 'arrows' pour ne pas avoir à te salir les mains avec des effects de bord.
Je ne suis pas aussi puriste que ça, quand j'écris:
let v1 = e1 and v2 = e2 in e3
je peux compter sur le fait que e1 sera évalué avant e2,
je n'ai pas besoin de monades ou de arrows pour maquiller la nature séquencielle de la chose.
Les 'arrows' me sont venues d'une façon qui me paraît tout de même moins "torturée" que ta présentation le suggère.
Voilà un exemple, où je pense être proche des 'arrows' et les utiliser intuitivement (et en particulier sans m'attacher à vérifier les fameuses lois) sans que rien ne soit motivé par un quelconque bling bling.
B et D étants les milieux respectifs de AC et CE, je cherche à démontrer Thalès, c'est-à-dire l'égalité vectorielle AE = 2×BD.
Voilà ce que ça donne, d'abord je déclare un type vecteur muni d'une addition :
Code Caml : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 type 'a vect_expr = | Vect of 'a * 'a | Add of 'a vect_expr * 'a vect_expr
Puis j'ajoute quelques équivalences et manipulations élémentaires:
Code Caml : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 (* AC = AB + BC *) let split b = function | Vect(a,c) -> Add (Vect(a,b),Vect(b,c)) | _ -> failwith "split" (* AB + BC = AC *) let merge = function | Add(Vect(a,b),Vect(c,d)) when b = c -> Vect(a,d) | _ -> failwith "merge" (* u + v = v + u *) let swap = function | Add(v1,v2) -> Add(v2,v1) | _ -> failwith "swap" (* u + (v + w) = (u + v) + w *) let rotate_right = function | Add(v1,Add(v2,v3)) -> Add(Add(v1,v2),v3) | _ -> failwith "rotate_right" (* (u + v) + w = u + (v + w) *) let rotate_left = function | Add(Add(v1,v2),v3) -> Add(v1,Add(v2,v3)) | _ -> failwith "rotate_left" (* target u in u + v *) let left f = function | Add(v1,v2) -> Add(f v1,v2) | _ -> failwith "left" (* target v in u + v *) let right f = function | Add(v1,v2) -> Add(v1,f v2) | _ -> failwith "right"
Les points qui m'intéressent:
Code Caml : Sélectionner tout - Visualiser dans une fenêtre à part type point = A | B | C | D | E
Leurs propriétés :
D'où mes égalités vectorielles, dans un sens et puis dans l'autre :
- B est le milieu de A et C.
- D est le milieu de C et E.
Une substitution me permet de jongler avec ces quantités égales:
Code Caml : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 let eq1 = [Vect(A,B),Vect(B,C);Vect(C,D),Vect(D,E)] let eq2 = [Vect(B,C),Vect(A,B);Vect(D,E),Vect(C,D)]
Code Caml : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 (* substitute equal values *) let substitute eq v = List.assoc v eq
Un 'pipe' (pour diminuer le nombre de parenthèses) :
Ma preuve:
Code : Sélectionner tout - Visualiser dans une fenêtre à part let (<|) x f = f x
Code Caml : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9 let thales_lemma v = v <| split B <| left (substitute eq1) <| right (split D) <| right (right (substitute eq2)) <| right swap <| rotate_right <| left merge
D'accord, ça n'est pas très lisible, mais vous pouvez facilement vous convaincre que c'est bien la preuve recherchée :
Autrement dit on a bien l'égalité AE = 2×BD.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 # Vect(A,E) <| thales_lemma;; - : point vect_expr = Add (Vect (B, D), Vect (B, D))
Il y a quelques redondances dans ma preuve.
On peut les éliminer à l'aide de l'opérateur de composition:
La preuve "simplifiée" devient:
Code Caml : Sélectionner tout - Visualiser dans une fenêtre à part let (<<) f g v = g (f v)
Code Caml : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7 let thales_lemma v = v <| split B <| left (substitute eq1) <| right (split D << right (substitute eq2) << swap) <| rotate_right <| left merge
À tort ou à raison, j'ai cru reconnaître ces fameuse 'arrows', par contre je ne vois pas ici où est le bling bling dont tu parles.
Bref, je reste sur ce même sentiment selon lequel les monades seraient plutôt "impératives" tandis que les flêches seraient bien davantage "fonctionnelles".
Partager