Основное назначение ньютайпов являются:
- Для определения альтернативных экземпляров для типов.
- Документация.
- Обеспечение достоверности данных/формата.
Я работаю над приложением прямо сейчас, когда я широко использую новые типы. newtypes
в Haskell - концепция чисто компиляции. Например. с развертками ниже, unFilename (Filename "x")
скомпилирован с тем же кодом, что и «x». Существует абсолютно нулевой врез. Существует с data
типами. Это делает его очень хорошим способом для достижения перечисленных выше целей.
-- | A file name (not a file path).
newtype Filename = Filename { unFilename :: String }
deriving (Show,Eq)
Я не хочу случайно рассматривать это как путь к файлу. Это не путь к файлу. Это название концептуального файла где-то в базе данных.
Очень важно, чтобы алгоритмы ссылались на нужную вещь, с этим справляются newtypes. Это также очень важно для безопасности, например, рассмотреть возможность загрузки файлов в веб-приложение. У меня есть эти типы:
-- | 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)
Предположим, у меня есть эта функция, которая чистит имя файла из файла, который был загружен:
-- | 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 "-_."
Теперь от сгенерировать уникальное имя файла:
-- | Generate a unique filename.
uniqueFilename :: SanitizedFilename --^Sanitized filename.
-> IO UniqueFilename --^Unique filename.
Опасно создавать уникальное имя файла из произвольного имени файла, его следует сначала очистить.Аналогичным образом, уникальное имя файла, таким образом, всегда безопасно по расширению. Я могу сохранить файл на диск сейчас и поместить это имя файла в свою базу данных, если захочу.
Но также может быть неприятно обертывать/разворачивать много. В конечном итоге я считаю, что это стоит того, чтобы избежать несоответствий стоимости. ViewPatterns помочь несколько:
-- | Get the form fields for a form.
formFields :: ConferenceId -> Controller [Field]
formFields (unConferenceId -> cid) = getFields where
... code using cid ..
Может быть, вы скажете, что разворачивать его в функции есть проблема - то, что если вы передаете cid
к функции неправильно? Не проблема, все функции, использующие идентификатор конференции, будут использовать тип ConferenceId. То, что возникает, - это своего рода система контрактов на уровне функций, которые вынуждены во время компиляции. Довольно приятно. Поэтому я использую его так часто, как могу, особенно в больших системах.
Hrm ... похоже, я не могу отметить более одного ответа, как принято. Я надеялся каким-то образом принять разумное представление о разных мнениях по этому вопросу ... – StevenC