2008-10-14 16 views
47

J'ai essayé d'expliquer la différence entre les instructions de commutation et la correspondance de modèle (F #) à un couple de personnes mais je n'ai pas vraiment été capable de l'expliquer bien la plupart du temps ils juste regarde-moi et dis "alors pourquoi tu n'utilises pas si ... alors ...".Explication de l'appariement de modèle vs commutateur

Comment les expliqueriez-vous?

EDIT! Merci à tous pour les bonnes réponses, j'aimerais vraiment pouvoir marquer plusieurs bonnes réponses.

Répondre

34

Ayant autrefois fait partie de "ces gens", je ne sais pas s'il existe une manière succincte de résumer pourquoi la mise en correspondance de motifs est une bonté si savoureuse. C'est expérientiel. À l'époque où je venais de jeter un coup d'œil sur la correspondance des motifs et que je pensais que c'était une instruction de commutation glorifiée, je ne savais pas programmer avec des types de données algébriques (tuples et unions discriminées). l'appariement de motifs était à la fois une construction de contrôle et une construction de liaison. Maintenant que j'ai programmé avec F #, j'ai finalement "compris". La fraîcheur de Pattern-matching est due à la confluence de fonctionnalités trouvées dans les langages de programmation fonctionnels, et il est donc non-trivial pour les outsiders d'apprécier.

J'ai essayé de résumer un aspect de la raison pour laquelle l'appariement de motifs est utile dans la seconde d'une courte série de blogs en deux parties sur le langage et la conception de l'API; consultez part one et part two.

+8

"expérientiel". Bon mot. :-) –

-1

Peut-être pourriez-vous faire une analogie avec les chaînes et les expressions régulières? Vous décrivez que vous recherchez, et laissez le compilateur calculer comment pour lui-même. Cela rend votre code beaucoup plus simple et clair. En aparté: Je trouve que la chose la plus utile à propos de l'appariement des motifs est qu'elle encourage les bonnes habitudes. Je traite avec les cas de coin d'abord, et il est facile de vérifier que j'ai couvert tous les cas.

5

Du haut de ma tête:

  1. Le compilateur peut dire si vous ne l'avez pas couvert toutes les possibilités dans vos matchs
  2. Vous pouvez utiliser un match comme une cession
  3. Si vous avez un union discriminée, chaque correspondance peut avoir un "type" différent
28

Les modèles vous donnent un petit langage pour décrire la structure des valeurs que vous voulez faire correspondre. La structure peut être arbitrairement profonde et vous pouvez lier des variables à des parties de la valeur structurée.

Ceci vous permet d'écrire des choses de manière extrêmement succincte. Vous pouvez illustrer cela avec un petit exemple, comme une fonction dérivée d'un type simple d'expressions mathématiques:

type expr = 
    | Int of int 
    | Var of string 
    | Add of expr * expr 
    | Mul of expr * expr;; 

let rec d(f, x) = 
    match f with 
    | Var y when x=y -> Int 1 
    | Int _ | Var _ -> Int 0 
    | Add(f, g) -> Add(d(f, x), d(g, x)) 
    | Mul(f, g) -> Add(Mul(f, d(g, x)), Mul(g, d(f, x)));; 

De plus, parce que la recherche de motifs est une construction statique pour les types statiques, le compilateur peut (i) vérifier que vous avez couvert tous les cas (ii) détecter les branches redondantes qui ne peuvent jamais correspondre à une valeur (iii) fournir une implémentation très efficace (avec des sauts, etc.).

+0

Bon exemple. En expliquant la correspondance des modèles avec les "personnes non-fonctionnelles", je tiens à mentionner qu'avec les PM votre condition peut vérifier la "forme" de vos données, ce qui est beaucoup plus difficile, laid et inefficace avec if/switch. –

+0

'Ajout de expr * expr' Je pense que vous vouliez écrire' + ' –

+2

Pas de lukas, c'est une syntaxe abstraite, pas une syntaxe concrète, donc' + 'est invalide et '*' ne devrait pas être interprété comme une multiplication arithmétique. 'Add of expr * expr' déclare un constructeur non constant' Add' dont les 2 arguments ont tous les deux le type 'expr'. Vous l'utilisez donc pour construire une combinaison de 2 expressions étiquetées comme 'Add'. –

4

Le commutateur est les deux roues avant.

L'appariement est la voiture entière.

+3

-1: Le commutateur est juste une roue. –

13

Extrait de this blog article:

Correspondance de modèle présente plusieurs avantages par rapport aux déclarations de commutation et l'expédition de la méthode:

  • motif correspond peut agir sur ints, flotteurs, cordes et autres types de ainsi que des objets.
  • Les correspondances de modèles peuvent agir simultanément sur plusieurs valeurs : correspondance de modèle parallèle. La méthode de répartition et de commutation est limitée à une seule valeur , par ex. "ce".
  • Les motifs peuvent être imbriqués, ce qui permet expédition sur les arbres de arbitraire profondeur. La répartition et le changement de méthode sont limités à au cas non imbriqué. Les modèles or permettent aux sous-modèles d'être partagés. L'envoi de la méthode permet uniquement le partage lorsque les méthodes proviennent de classes qui partagent une classe de base . Sinon, vous devez manuellement factoriser la communalité dans une fonction séparée (en lui donnant un nom), puis insérez manuellement les appels de tous les endroits appropriés à votre fonction inutile .
  • La correspondance de modèle fournit la redondance qui vérifie les erreurs.
  • Les correspondances imbriquées et/ou parallèles sont optimisées pour vous par le compilateur F # . L'équivalent OO doit être écrit à la main et constamment réoptimisé à la main au cours développement, ce qui est prohibitif fastidieux et source d'erreurs si code OO-qualité de la production tend à être extrêmement lent en comparaison.
  • Les modèles actifs vous permettent d'injecter sémantique de répartition personnalisée.
3

Les correspondances de modèles dans OCaml, en plus d'être plus expressives comme mentionné de plusieurs manières qui ont été décrites ci-dessus, donnent également des garanties statiques très importantes. Le compilateur se révélera pour vous que le cas l'analyse incarnée par votre déclaration modèle-match:

  • exhaustive (aucun cas sont manqués)
  • non redondants (aucun cas qui ne peut jamais être frappé parce qu'ils sont préempté par un cas précédent)
  • son (pas de modèles impossibles étant donné le type de données en question)

C'est vraiment un grand. C'est utile lorsque vous écrivez le programme pour la première fois, et extrêmement utile lorsque votre programme évolue. Utilisées correctement, les instructions de correspondance facilitent la modification fiable des types dans votre code, car le système de types vous pointe sur les instructions de correspondance brisées, qui sont un indicateur décent de l'endroit où vous avez du code à corriger.

5

Les tuples ont "," et les variantes ont des arguments Ctor.ce sont des constructeurs, ils créent des choses.

Les motifs sont des destructeurs, ils les déchirent.

Ce sont des concepts doubles. Pour mettre ceci plus fortement: la notion de tuple ou de variante ne peut pas être décrite simplement par son constructeur: le destructeur est requis ou la valeur que vous avez faite est inutile. Ce sont ces deux descriptions qui définissent une valeur.

Généralement, nous considérons les constructeurs comme des données, et les destructeurs comme des flux de contrôle. Les destructeurs de variantes sont des branches alternatives (une parmi de nombreuses), les destructeurs de tuple sont des fils parallèles (tous de plusieurs).

Le parallélisme est évident dans les opérations comme

(f * g) . (h * k) = (f . h * g . k) 

si vous pensez de commande circulant à travers une fonction, tuples fournissent un moyen pour diviser un calcul en fils parallèles de contrôle.

Considérées de cette façon, les expressions sont des façons de composer des tuples et des variantes pour créer des structures de données complexes (pensez à un AST).

Et les correspondances de motifs sont des façons de composer les destructeurs (encore une fois, pensez à un AST).

0

Les instructions If-Else (ou switch) concernent le choix de différentes façons de traiter une valeur (entrée) en fonction des propriétés de la valeur disponible. La correspondance de modèle consiste à définir comment traiter une valeur étant donné sa structure , (notez également que les correspondances de cas uniques ont un sens). Ainsi, l'appariement de formes consiste plus à déconstruire des valeurs qu'à faire des choix, ce qui en fait un mécanisme très pratique pour définir des fonctions (récursives) sur des structures inductives (types d'union récursifs), ce qui explique leur utilisation abondante dans des langages comme Ocaml. PS: Vous pouvez connaître les "patterns" de pattern-match et de If-Else à partir de leur utilisation ad-hoc en math;

"si x a la propriété A alors y z d'autre" (If-Else)

"un terme à p1..pn où .... est la décomposition de premier x .." ((seul cas) correspondance de motif)