2010-08-13 12 views
11

Se si confronta una stringa letterale con una stringa letterale utilizzando l'istruzione case, ottengo il comportamento previsto: se sono uguali - corrisponde, se non lo sono - non lo fa .Variabili di pattern matching in un'istruzione case in Haskell

Tuttavia, se si confronta una stringa letterale con una costante che è una stringa, viene visualizzato l'avviso "Motivo ripetuto sovrapposto" e il ramo con la costante corrisponde sempre.

Ecco una sessione di esempio:

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" 

Nel frattempo, se si comporta come previsto:

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

cosa sta succedendo qui? Come ha senso questo comportamento?

+0

Grazie, signori. Hai spiegato sia cosa stava succedendo che come abbinare una stringa di input a valori codificati. –

+1

Desidero documentazione e varie esercitazioni in cui esplicito che a) l'affermazione del caso è modello che corrisponde a una sintassi diversa eb) diversa dalla somiglianza superficiale Il caso di Haskell non ha nulla in comune con l'interruttore di C. Risolvono diversi problemi. –

+0

Questo è anche spiegato nel libro (gratuito) [Real World Haskell] (http://book.realworldhaskell.org/read/defining-types-streamlining-functions.html#id587485). – Flow

risposta

8

Questo perché il "caso" non sta facendo quello che pensi sia. La "var2" impostata su "def" non viene confrontata con "var1". Invece stai ricevendo un nuovo scope contenente una nuova "var2" che è legata al valore di "var1".

Il motivo del messaggio di errore è che per quanto riguarda il compilatore non c'è differenza tra "var2 -> ..." e "_ -> ...". Entrambi corrispondono a tutti i possibili valori di "var1".

+0

Penso che sarebbe utile per voi spiegare come farlo simbolicamente con le variabili, o per spiegare quale sia la teoria o il ragionamento per la scelta di questo comportamento. –

+0

* Sigh * +1 Ho davvero bisogno di imparare a digitare più velocemente. –

+1

@ Evan, penso che il ragionamento riguardi la conversione alfa. Cioè, non vogliamo che la decisione di qualcuno di aggiungere un binding di livello superiore per 'x' per cambiare drasticamente la semantica delle nostre corrispondenze di pattern. – luqui

18

Pattern matching in Haskell associa nuove variabili. Quindi quando scrivi:

case x of 
    y -> ... 

ora hai associato una nuova variabile 'y' al valore di 'x'. Questo è il "modello" banale. Si può vedere più chiaramente come le opere di legame quando un costruttore è coinvolto:

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

Ora a e b si legano ai componenti della tupla. E così via per decostruire e legare altri tipi di dati. Così, per abbinare una stringa letterale, si può scrivere:

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

Penso di aver letto questo prima - Sono ancora sul palco dove sto cercando di imparare Haskell - il tuo esempio di decostruzione è stato il "Oh, ecco perché" per me. –

21

la risposta di Don Sede per il motivo. Un linguaggio comune per fare quello che si sta cercando di fare è questo:

var1 = "abc" 
var2 = "def" 

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

Naturalmente in questo caso si perderebbe il case e basta scrivere le guardie direttamente sulla funzione:

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

UPDATE

In questi giorni l'estensione MultiWayIf fa questo con un rumore leggermente meno sintattico.

{-# LANGUAGE MultiWayIf #-} 

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