2012-06-05 21 views
7

tengo este tipo de datospatrón constructor Haskell juego

data Struct val = Empty | Exec1 val 
         | Exec2 val 

Y dos funciones ficticias

apply :: Struct -> String 
apply (Empty) = "matched Empty" 
apply (exec struct) = "matched Exec1 or Exec2"    

apply' :: Struct val -> String 
apply' (Empty) = "matched Empty" 
apply' (Exec1 _) = "matched Exec1" 
apply' (Exec2 _) = "matched Exec2" 

segundo está trabajando muy bien, pero el primero es la causa de error: "Error de análisis de patrón: ejecutivo ". ¿Puedes explicar por qué no puedo hacer coincidir el constructor de esta manera: apply (exec struct) = ...?

Está causando una gran cantidad de código repetitivo cuando tengo varios constructores en mi tipo de datos y debo adaptarlos por separado.

Respuesta

3

¿Por qué? Como solo puede hacer coincidir constructores, y exec es una especie de nueva variable. Una razón de esto es por ejemplo el siguiente:

data Struct2 = Empty | Exec1 String 
         | Exec2 Int 

apply :: Struct2 -> String 
apply Empty = "matched Empty" 
apply (exec struct) = ?? 

Cómo alguien debería saber cuál de Exec1 y Exec2 que son coincidentes? No se pudieron aplicar funciones aquí, ya que no se pudo determinar el tipo real de struct.

Si desea reducir la coincidencia de patrones, existen varias maneras, desde el uso de case, a través de la implementación de data diferente (como @Karolis sugerido) y funciones auxiliares a construcciones de nivel superior con tipos más complejos. Pero ese es un tema interminable.

3

"exec" no es un constructor de tipos y solo puede usarlos en la coincidencia de patrones.

Lo que puede hacer es

data Struct val = Empty | Exec Int val 

apply :: Struct -> String 
apply (Empty) = "matched Empty" 
apply (Exec _ _) = "matched Exec1 or Exec2"    

apply' :: Struct val -> String 
apply' (Empty) = "matched Empty" 
apply' (Exec 1 _) = "matched Exec1" 
apply' (Exec 2 _) = "matched Exec2" 
19

En general, si usted tiene varios constructores que comparten datos, a continuación, por lo general es mejor refactorizar la declaración de datos a algo así como

data Struct val = Empty | NonEmpty StructType val 
data StructType = Exec1 | Exec2 

que ahora podemos reconocer patrón en apply como esto

apply :: Struct -> String 
apply (Empty) = "matched Empty" 
apply (NonEmpty exec struct) = "matched Exec1 or Exec2" 

y aún puede también coincidir con un tipo de Exec específico

apply' :: Struct val -> String 
apply' (Empty) = "matched Empty" 
apply' (NonEmpty Exec1 _) = "matched Exec1" 
apply' (NonEmpty Exec2 _) = "matched Exec2" 
+2

Incluso podría ser una buena idea reutilizar el tipo 'Maybe' predefinido en esta situación. – dflemstr

1

En su caso particular, puede hacer lo siguiente:

apply :: Struct -> String 
apply Empty = "matched Empty" 
apply _  = "matched Exec1 or Exec2" 

Esto no va a escalar muy bien a resultados más complicados sin embargo.

0
apply Empty = "matched empty" 
apply (Exec1 _) = notEmpty 
apply (Exec2 _) = notEmpty 

notEmpty = "matched Exec1 or Exec2" 
Cuestiones relacionadas