Los principales usos para Newtypes son:
- Para la definición de casos alternativos para los tipos.
- Documentación.
- Garantía de corrección de datos/formatos.
Estoy trabajando en una aplicación en este momento en la que uso newtypes de manera exhaustiva. newtypes
en Haskell son un concepto puramente de tiempo de compilación. P.ej. con los desempaquetadores a continuación, unFilename (Filename "x")
compilados con el mismo código que "x". No hay absolutamente ningún hit de tiempo de ejecución. Hay con data
tipos. Esto lo convierte en una forma muy agradable de lograr los objetivos enumerados anteriormente.
-- | A file name (not a file path).
newtype Filename = Filename { unFilename :: String }
deriving (Show,Eq)
No quiero tratar accidentalmente esto como una ruta de archivo. No es una ruta de archivo. Es el nombre de un archivo conceptual en algún lugar de la base de datos.
Es muy importante que los algoritmos hagan referencia a lo correcto, los nuevos tipos ayudan con esto. También es muy importante para la seguridad, por ejemplo, considerar la carga de archivos a una aplicación web. Tengo estos tipos:
-- | A sanitized (safe) filename.
newtype SanitizedFilename =
SanitizedFilename { unSafe :: String } deriving Show
-- | Unique, sanitized filename.
newtype UniqueFilename =
UniqueFilename { unUnique :: SanitizedFilename } deriving Show
-- | An uploaded file.
data File = File {
file_name :: String --^Uploaded file.
,file_location :: UniqueFilename --^Saved location.
,file_type :: String --^File type.
} deriving (Show)
Supongamos que tengo esta función que limpia un nombre de archivo de un archivo que se ha subido:
-- | Sanitize a filename for saving to upload directory.
sanitizeFilename :: String --^Arbitrary filename.
-> SanitizedFilename --^Sanitized filename.
sanitizeFilename = SanitizedFilename . filter ok where
ok c = isDigit c || isLetter c || elem c "-_."
Ahora a partir de ese genero un nombre de archivo único:
-- | Generate a unique filename.
uniqueFilename :: SanitizedFilename --^Sanitized filename.
-> IO UniqueFilename --^Unique filename.
Es peligroso generar un nombre de archivo único a partir de un nombre de archivo arbitrario, primero debe desinfectarse.Del mismo modo, un nombre de archivo único siempre es seguro por extensión. Puedo guardar el archivo en el disco ahora y poner ese nombre de archivo en mi base de datos si quiero.
Pero también puede ser molesto tener que envolver/desenvolver un montón. A la larga, creo que vale la pena, especialmente para evitar desajustes de valores. ViewPatterns ayudar un poco:
-- | Get the form fields for a form.
formFields :: ConferenceId -> Controller [Field]
formFields (unConferenceId -> cid) = getFields where
... code using cid ..
Tal vez quiera decir que desenvolver en una función es un problema - lo que si se pasa a una función cid
erróneamente? No es un problema, todas las funciones que usan una identificación de conferencia usarán el tipo ConferenceId. Lo que surge es una especie de sistema de contrato de función a función que se ve forzado en tiempo de compilación. Bastante agradable. Así que sí lo uso tan a menudo como puedo, especialmente en sistemas grandes.
Hrm ... Parece que no puedo marcar más de una respuesta como aceptada. Esperaba de alguna manera aceptar una representación razonable de las diferentes opiniones sobre este tema ... – StevenC