2010-08-13 21 views
11

Si je compare une chaîne littérale à une chaîne littérale utilisant l'instruction de cas, je reçois le comportement attendu: si elles sont les mêmes - il correspond, si elles ne sont pas - il n'a pas .les variables correspondant à motif dans une déclaration de cas dans Haskell

Cependant, si je compare une chaîne littérale à une constante qui est une chaîne, je reçois « matches de motif se chevauchent » avertissement et la branche avec la constante correspond toujours.

Voici un exemple de session:

Prelude> let var1 = "abc" 
Prelude> let var2 = "def" 
Prelude> case var1 of { var2 -> "Fail"; _ -> "Win" } 

<interactive>:1:0: 
    Warning: Pattern match(es) are overlapped 
      In a case alternative: _ -> ... 
"Fail" 
Prelude> case "abc" of { var2 -> "Fail"; _ -> "Win" } 

<interactive>:1:0: 
    Warning: Pattern match(es) are overlapped 
      In a case alternative: _ -> ... 
"Fail" 
Prelude> case "abc" of { "def" -> "Fail"; _ -> "Win" } 
"Win" 

Pendant ce temps, se comporte comme prévu:

> Prelude> if var1 == var2 then "Fail" else "Win" 
"Win" 

Qu'est-ce qui se passe ici? Comment ce comportement a-t-il un sens?

+0

Merci, messieurs. Vous avez expliqué à la fois ce qui se passait et comment faire correspondre une chaîne d'entrée avec des valeurs codées en dur. –

+1

Je souhaite que la documentation et divers didacticiels expliquent explicitement que a) l'instruction case correspond à une syntaxe différente et b) autre que la similarité superficielle Le cas de Haskell n'a rien de commun avec le commutateur de C. Ils résolvent différents problèmes. –

+0

Ceci est également bien expliqué dans le livre (gratuit) [Real World Haskell] (http://book.realworldhaskell.org/read/defining-types-streamlining-functions.html#id587485). – Flow

Répondre

8

C'est parce que le « cas » ne fait pas ce que vous pensez qu'il est. Le "var2" qui a été mis à "def" n'est pas comparé à "var1". Au lieu de cela, vous obtenez une nouvelle portée contenant un nouveau "var2" qui est lié à la valeur de "var1".

La raison du message d'erreur est que dans la mesure où le compilateur est concerné il n'y a pas de différence entre « var2 -> ... » et « _ -> ... ». Les deux correspondent à toutes les valeurs possibles de "var1".

+0

Je pense qu'il serait utile pour vous d'expliquer comment le faire symboliquement avec des variables, ou d'expliquer quelle est la théorie ou le raisonnement pour choisir ce comportement. –

+0

* Soupir * +1 J'ai vraiment besoin d'apprendre à taper plus vite. –

+1

@Evan, je pense que le raisonnement est sur la conversion alpha. C'est-à-dire que nous ne voulons pas que la décision de quelqu'un d'ajouter une reliure de haut niveau pour 'x' change radicalement la sémantique de nos correspondances. – luqui

18

Pattern matching in Haskell se fixe de nouvelles variables. Donc, quand vous écrivez:

case x of 
    y -> ... 

vous avez maintenant lié une nouvelle variable 'y' à la valeur de 'x'. C'est le "modèle" trivial. Vous pouvez voir plus clairement comment les travaux de liaison lorsqu'un constructeur est impliqué:

case x of 
    (a, b) -> ... 

maintenant a et b se lient à des composants du tuple. Et ainsi de suite pour déconstruire et lier d'autres types de données. Ainsi, pour correspondre à une chaîne de caractères, vous pouvez écrire:

case x of 
    "def" -> .... 
+0

Je pense que j'ai déjà lu ceci - je suis encore au stade où j'essaie d'apprendre Haskell - votre exemple avec la déconstruction était le "Oh, c'est pourquoi" pour moi. –

21

Voir la réponse Don pourquoi. Un idiome commun pour faire ce que vous essayez de faire est la suivante:

var1 = "abc" 
var2 = "def" 

foo x = case() of 
    () | x == var1 -> "Fail" 
     | x == var2 -> "Failzor" 
     | otherwise -> "WIN" 

Bien sûr, dans ce cas, nous perdrions la case et il suffit d'écrire les gardes directement sur la fonction:

foo x | x == var1 = "Fail" 
     | ... 

MISE À JOUR

Ces jours-ci, l'extension MultiWayIf le fait avec un bruit légèrement moins syntaxique.

{-# LANGUAGE MultiWayIf #-} 

foo x = if | x == var1 -> "Fail" 
      | x == var2 -> "Failzor" 
      | otherwise -> "WIN"