Précédent   Forum des professionnels en informatique > Autres langages > Langages fonctionnels > Caml
Caml Forum d'entraide sur la programmation avec les langages fonctionnels Caml-Light et OCaml
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Proposer ce sujet en actualité
 
Outils de la discussion
Publicité
'
Vieux 29/01/2012, 16h25   #1
Membre régulier
 
Inscription : mai 2009
Messages : 247
Détails du profil
Informations forums :
Inscription : mai 2009
Messages : 247
Points : 96
Points : 96
Par défaut Pattern matching dynamique

Je me demandais s'il existe un moyen de faire du pattern matching configurable à l’exécution plutôt qu'à la compilation

par exemple à la compilation on a :
Code :
1
2
3
4
5
6
let handle item = match item with
   | 1 -> "Do this";
   | 2 -> "Do that";
   | n -> "Do Nothing";
;;
j'aimerais pouvoir faire un truc du genre :

Code :
1
2
3
4
5
6
7
8
9
10
11
12
let list = [(1, "Do this\n"); (2, "Do that\n")];;

let handle l =
let rec rhandle l = match l with
   | [] -> "Empty list"
   | (i, s)::rest -> print_string s; rhandle rest
   | (n, s)::rest -> "Do Nothing" in

rhandle l
;;

handle list;;
pour qu'à chaque entier d'un couple, la chaine associée soit affichée (ou la même chose mais avec une fonction)

de façon plus élégante et standard évidemment

ou même mieux, pouvoir paramétrer le type de i et que la pattern matching détermine automatiquement ce que c'est :

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

type items = itemA | itemB;; 

let list = [(itemA, "itemA\n"); (itemB, "itemB\n")];;

let handle l =
let rec rhandle l = match l with
   | [] -> "Empty list"
   | (i : items, s)::rest -> print_string s; rhandle rest
   | (n, s)::rest -> "Do Nothing" in

rhandle l
;;

handle list;;
en fait mon but est d'émuler le pattern chaine de responsabilité mais avec les avantages syntaxiques d'Ocaml
coda_blank est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 29/01/2012, 18h30   #2
Membre émérite
 
Inscription : avril 2007
Messages : 814
Détails du profil
Informations forums :
Inscription : avril 2007
Messages : 814
Points : 976
Points : 976
Je n'ai pas compris ce que tu veux, à part la fin "chaîne de responsabilité".

Du coup j'ai écrit un peu de code pour faire un truc qui ressemble, mais je ne sais pas si ça correspond à ce que tu demandes, vu que je n'ai pas bien compris ce que tu voulais.

Code :
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
35
36
37
type ('a, 'b) decision =
  | PassNext of 'a
  | Return of 'b

let rec eval handlers arg = match handlers with
  | [] -> failwith "no handlers"
  | h::rest ->
    match h arg with
      | Return ret -> ret
      | PassNext new_arg -> eval rest new_arg

let filter cond handler = fun arg ->
  if cond arg then handler arg else PassNext arg

let passnext f = fun arg -> PassNext (f arg)
let return f = fun arg -> Return (f arg)

let watcher name = fun arg ->
  Printf.printf "%s: saw %d\n" name arg;
  PassNext arg

let () =
  let handlers = [
    watcher "h1";
    filter (fun n -> n mod 2 = 0) (watcher "h2");
    filter (fun n -> n > 10) (return ((+) 2));
    passnext ((+) 1);
    watcher "h3";
    return (fun _ -> 0);
  ] in
  let test arg =
    print_endline "eval...";
    let result = eval handlers arg in
    Printf.printf "result: %d\n\n" result in
  test 3;
  test 4;
  test 21
gasche est déconnecté   Envoyer un message privé Réponse avec citation 01
Vieux 29/01/2012, 20h47   #3
Membre régulier
 
Inscription : mai 2009
Messages : 247
Détails du profil
Informations forums :
Inscription : mai 2009
Messages : 247
Points : 96
Points : 96
Citation:
Envoyé par gasche Voir le message
Je n'ai pas compris ce que tu veux, à part la fin "chaîne de responsabilité".

Du coup j'ai écrit un peu de code pour faire un truc qui ressemble, mais je ne sais pas si ça correspond à ce que tu demandes, vu que je n'ai pas bien compris ce que tu voulais.

Code :
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
35
36
37
type ('a, 'b) decision =
  | PassNext of 'a
  | Return of 'b

let rec eval handlers arg = match handlers with
  | [] -> failwith "no handlers"
  | h::rest ->
    match h arg with
      | Return ret -> ret
      | PassNext new_arg -> eval rest new_arg

let filter cond handler = fun arg ->
  if cond arg then handler arg else PassNext arg

let passnext f = fun arg -> PassNext (f arg)
let return f = fun arg -> Return (f arg)

let watcher name = fun arg ->
  Printf.printf "%s: saw %d\n" name arg;
  PassNext arg

let () =
  let handlers = [
    watcher "h1";
    filter (fun n -> n mod 2 = 0) (watcher "h2");
    filter (fun n -> n > 10) (return ((+) 2));
    passnext ((+) 1);
    watcher "h3";
    return (fun _ -> 0);
  ] in
  let test arg =
    print_endline "eval...";
    let result = eval handlers arg in
    Printf.printf "result: %d\n\n" result in
  test 3;
  test 4;
  test 21
je ne comprend pas trop à quoi servent passnext et return

EDIT : ah ok return stoppe l'évaluation et passnext passe au suivant

bon ça correspond à ce que je demandais, une liste de handlers-conditions qui catchent ou non un argument (chaine de responsabilité)

par contre est-ce qu'il possible de filtrer selon le type de l'argument ?

par ex si j'ai :

Code :
type event = EventA |EventB
et que je veux :

Code :
1
2
filter (fun event -> event of EventA) (watcher "EventA");
filter (fun event -> event of EventB) (watcher "EventB");
comment m'y prendre ?

niveau performances, c'est plus lent qu'un pattern matching classique ?
coda_blank est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 30/01/2012, 10h11   #4
Membre habitué
 
Avatar de Ptival
 
Homme Valentin Robert
Ingénieur développement logiciels
Inscription : juin 2004
Messages : 53
Détails du profil
Informations personnelles :
Nom : Homme Valentin Robert
Âge : 23
Localisation : France, Yvelines (Île de France)

Informations professionnelles :
Activité : Ingénieur développement logiciels
Secteur : High Tech - Éditeur de logiciels

Informations forums :
Inscription : juin 2004
Messages : 53
Points : 125
Points : 125
Code :
1
2
3
4
5
6
7
isEventA = function EventA -> true | _ -> false
isEventB = function EventB -> true | _ -> false

[...]

filter isEventA (watcher "EventAhandler");
Ptival est déconnecté   Envoyer un message privé Réponse avec citation 10
Vieux 30/01/2012, 14h50   #5
Membre régulier
 
Inscription : mai 2009
Messages : 247
Détails du profil
Informations forums :
Inscription : mai 2009
Messages : 247
Points : 96
Points : 96
Citation:
Envoyé par Ptival Voir le message
Code :
1
2
3
4
5
6
7
isEventA = function EventA -> true | _ -> false
isEventB = function EventB -> true | _ -> false

[...]

filter isEventA (watcher "EventAhandler");
ok, merci

il y a un autre situation qui me chiffonne : une hiérarchie de variants

mettons que j'ai :

Code :
1
2
3
4
5
6
7
8
9
type subEvent=
	| EventA
	| EventB
;;

type event = 
	| EventAA of EventA
	| EventBB of EventB
;;
vu que dans une liste on ne peut placer que des éléments de même type, je ne pourrai pas mettre au même niveau un subEvent et un event
coda_blank est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 30/01/2012, 15h12   #6
Membre habitué
 
Avatar de Ptival
 
Homme Valentin Robert
Ingénieur développement logiciels
Inscription : juin 2004
Messages : 53
Détails du profil
Informations personnelles :
Nom : Homme Valentin Robert
Âge : 23
Localisation : France, Yvelines (Île de France)

Informations professionnelles :
Activité : Ingénieur développement logiciels
Secteur : High Tech - Éditeur de logiciels

Informations forums :
Inscription : juin 2004
Messages : 53
Points : 125
Points : 125
Je crois que la solution "ad hoc" et "simple" est de les envelopper dans un type somme :

Code :
1
2
3
4
type events =
| Event of event
| SubEvent of subEvent
et de créer une liste d'Une solution plus "avancée" consisterait à exploiter les variants polymorphes, je pense, mais je ne suis pas certain que ce soit la bonne solution (je laisse aux autres le soin de compléter).
Ptival est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 13h52.


 
 
 
 
Partenaires

Hébergement Web