2010-08-13 12 views
11

Si comparo un literal de cadena con un literal de cadena utilizando la sentencia case, obtengo el comportamiento esperado: si son iguales - coincide, si no lo son - no lo hace .Variables de coincidencia de patrón en una declaración de caso en Haskell

Sin embargo, si comparo un literal de cadena con una constante que es una cadena, aparece la advertencia "Las coincidencias de patrón están superpuestas" y la rama con la constante siempre coincide.

He aquí un ejemplo de sesión:

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" 

Mientras tanto, si se comporta como se esperaba:

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

lo que está pasando aquí? ¿Cómo tiene sentido este comportamiento?

+0

Gracias, señores. Explicó qué estaba pasando y cómo hacer coincidir una cadena de entrada con valores codificados. –

+1

Deseo documentación y varios tutoriales donde explícitamente a) declaración de caso es coincidencia de patrones con una sintaxis diferente yb) distinta de similitud superficial El caso de Haskell no tiene nada en común con el cambio de C. Ellos resuelven diferentes problemas. –

+0

Esto también está bien explicado en el libro (gratuito) [Real World Haskell] (http://book.realworldhaskell.org/read/defining-types-streamlining-functions.html#id587485). – Flow

Respuesta

8

Eso es porque el "caso" no está haciendo lo que usted cree que es. El "var2" que se configuró en "def" no se compara con "var1". En su lugar, obtiene un nuevo ámbito que contiene un nuevo "var2" que está vinculado al valor de "var1".

El motivo del mensaje de error es que, en lo que respecta al compilador, no hay diferencia entre "var2 -> ..." y "_ -> ...". Ambos coinciden con todos los valores posibles de "var1".

+0

Creo que sería útil para usted explicar cómo hacerlo simbólicamente con variables, o explicar cuál es la teoría o el razonamiento para elegir este comportamiento. –

+0

* Suspiro * +1 Realmente necesito aprender a escribir más rápido. –

+1

@Evan, creo que el razonamiento es acerca de la conversión alfa. Es decir, no queremos que la decisión de alguien agregue un enlace de nivel superior para 'x' para cambiar drásticamente la semántica de nuestras coincidencias de patrones. – luqui

18

Pattern matching in Haskell vincula nuevas variables. Por lo tanto, cuando escriba:

case x of 
    y -> ... 

, ahora ha vinculado una nueva variable 'y' al valor de 'x'. Este es el "patrón" trivial. Se puede ver más claramente cómo funciona la encuadernación Cuando un constructor está involucrado:

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

Ahora A y B se unen a los componentes de la tupla. Y así sucesivamente para deconstruir y vincular otros tipos de datos. Por lo tanto, para que coincida con una cadena literal, podría escribir:

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

Creo que leí esto antes, todavía estoy en la etapa en la que intento aprender Haskell, tu ejemplo con la deconstrucción fue el "Oh, es por eso" para mí. –

21

Véase la respuesta de Don por qué. Un lenguaje común para hacer lo que usted está tratando de hacer es lo siguiente:

var1 = "abc" 
var2 = "def" 

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

Por supuesto, en este caso perderíamos la case y acaba de escribir los guardias directamente en la función:

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

ACTUALIZACIÓN

En estos días, la extensión MultiWayIf hace esto con un ruido sintáctico ligeramente menor.

{-# LANGUAGE MultiWayIf #-} 

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