2011-12-24 7 views
9

Tengo el siguiente registro definido:Haskell campos "dependientes" de un registro?

data Option = Option { 
    a :: Maybe String, 
    b :: Either String Int 
} deriving (Show) 

¿Hay alguna forma para mí de hacer cumplir que cuando a es Nothing, B debe ser un Left y cuando a es Just, B debe ser un Right? Tal vez con tipos fantasmas, o algo más? ¿O debo envolver todo dentro de un O bien y hacerlo Either String (String, Int)?

+0

No creo que Haskell 2010 tenga nada que permita esto en su solución anterior. Sugeriría ir por 'Either String (String, Int)', o un tipo isomorfo como 'data Option = OptionA String | OptionB String Int', donde los constructores tienen nombres razonables. –

+1

Para responder mejor a esto, es importante saber el * significado * adjunto a 'a' y' b'. ¿Por qué a veces no tienes un 'a' (por ejemplo,' Nada')? ¿Por qué está bien representar 'b' como' String' * o * an 'Int'? ¿Por qué quieres hacer cumplir la restricción de la que hablabas? Esto me da la impresión inicial de que 'b' no está bien definido. –

Respuesta

17

Usted sólo debe utilizar dos constructores para las dos formas posibles:

data Option = NoA String | WithA String Int 

Por supuesto, se les debe dar mejores nombres, sobre la base de lo que representan. Los tipos de fantasmas son definitivamente exagerados aquí, y sugiero evitar Either - Left y Right no son nombres de constructor muy autodocumentados.

Si tiene sentido para interpretar ambos Cualquiera de las ramas del campo B como la representación de los mismos datos, entonces usted debe definir una función que refleja esta interpretación:

b :: Option -> MeaningOfB 
b (NoA s) = ... 
b (WithA t n) = ... 

Si tiene campos que se mantienen los mismos sin Independientemente de la elección, debe crear un nuevo tipo de datos con todos ellos e incluirlo en ambos constructores. Si hace que cada constructor sea un registro, puede asignar el mismo nombre al campo común en cada constructor, de modo que pueda extraerlo de cualquier valor Option sin tener que hacer coincidir patrones en él.

Básicamente, piensa en lo que significa para la cadena de no estar presente: ¿qué van cambiando en los otros campos, y lo que sigue siendo el mismo? Cualquier cambio debe ir en los respectivos constructores; lo que sea que permanezca igual se debe tener en cuenta en su propio tipo. (¡Este es un buen principio de diseño en general!)

Si viene de un fondo OOP, puede pensar en esto en términos de razonamiento con composición en lugar de herencia, pero trate de no tomar la analogía demasiado lejos.

Cuestiones relacionadas