2012-01-18 12 views
9

Como estaba writing up an answer hace un momento, me encontré con un problema interesante:Registro valor predeterminado sintaxis de descriptor de acceso

data Gender = Male | Female 
      deriving (Eq, Show) 

data Age = Baby | Child | PreTeen | Adult 
     deriving (Eq, Show, Ord) 

data Clothing = Pants Gender Age 
       | Shirt Gender Age 
       | Skirt Age   -- assumed to be Female 
       deriving (Show, Eq) 

Supongamos que desea escribir el tipo de datos final con la sintaxis de registro:

data Clothing = Pants {gender :: Gender, age :: Age} 
       | Shirt {gender :: Gender, age :: Age} 
       | Skirt {age :: Age} 
       deriving (Show, Eq) 

El problema es que quiero gender $ Skirt foo para evaluar siempre a Female (independientemente de foo, que es un Age). Puedo pensar en algunas maneras de lograr esto, pero requieren que sea

  1. uso constructores inteligentes, teóricamente permitiendo Skirt Male foo pero no exponer constructores
  2. definir mi propia gender función

Con # 1, al no exponer el constructor en el módulo, evito efectivamente que los usuarios del módulo aprovechen la sintaxis del registro. Con el n. ° 2, debo renunciar por completo a la sintaxis del registro o definir una función adicional gender', que de nuevo vence la sintaxis del registro.

¿Hay alguna manera de aprovechar la sintaxis del registro y también proporcionar un valor "predeterminado" e inmutable para uno de mis constructores? También estoy abierto a soluciones sin sintaxis de registro (¿lentes, quizás?) Siempre y cuando sean igual de elegantes (o más).

+4

Una lente normal no funcionaría, ya que puede asignar el campo 'gender' con dos de los constructores, pero no con el otro. Creo que hacer esto es una mala idea; si 'foo' es un descriptor de acceso de registro, y' foo x' funciona, entonces 'x {foo = y}' también debería. – ehird

+0

Suele ir con 2. – augustss

+0

¿Cómo se ve la adición de una función 'gender'' (o podría llamarlo' totalGender' o 'safeGender' más o menos) ¿derrota la sintaxis del registro? –

Respuesta

0

¿Hay alguna manera de aprovechar la sintaxis del registro, y también proporcionar un valor "predeterminado" e inmutable para uno de mis constructores?

En ausencia de un contraejemplo convincente, la respuesta parece ser "no".

0

Sí, existe una tensión entre tipos y datos ... que por cierto muestra qué tan delgada es la línea.

La respuesta práctica es utilizar una instancia predeterminada como se indica en Haskell Wiki. Responde tu pregunta exacta ya que debes renunciar al uso directo del constructor.

Así, por tu ejemplo,

data Age = Baby | Child | PreTeen | Adult | NoAge 
data Clothing = Pants {gender :: Gender, age :: Age} 
       | Shirt {gender :: Gender, age :: Age} 
       | Skirt {gender :: Gender, age :: Age} 
       deriving (Show, Eq) 

skirt = Skirt { gender=Female, age=NoAge } 

continuación, desarrolladores de pueden crear nuevas instancias con valores predeterminados, usando la facilidad de copiar y actualización de la sintaxis de registro

newSkirt = skirt { age=Adult } 

y gender newSkirt evalúa a Female

Quiero recalcar que este enfoque lo lleva a definir valores predeterminados en el nivel de tipo, que creo que es un Buena cosa (por supuesto, el NoAge constructor es el Nothing de un tipo Maybe Age).

Cuestiones relacionadas