gpt4 book ai didi

就类型安全而言,Haskell 类型与 newtype

转载 作者:行者123 更新时间:2023-12-02 06:57:53 24 4
gpt4 key购买 nike

我知道newtype更多时候与 data 进行比较在 Haskell 中,但我更多地是从设计角度而不是技术问题来进行这种比较。

在命令式/面向对象语言中,存在反模式“primitive obsession”,其中大量使用原始类型会降低程序的类型安全性,并意外地引入相同类型值的可互换性,否则本应用于不同的值目的。例如,很多东西都可以是字符串,但如果编译器能够静态地知道哪些是名称,哪些是地址中的城市,那就太好了。

那么,Haskell 程序员多久雇佣一次 newtype为其他原始值提供类型区别?使用type引入别名并为程序的可读性提供更清晰的语义,但不能防止意外的值交换。当我学习 Haskell 时,我注意到该类型系统与我遇到的任何类型系统一样强大。因此,我认为这是一种自然且常见的做法,但我还没有看到太多或任何关于 newtype 的使用的讨论。从这个角度来看。

当然,很多程序员的做法不同,但这在 haskell 中常见吗?

最佳答案

新类型的主要用途是:

  1. 用于定义类型的替代实例。
  2. 文档。
  3. 数据/格式正确性保证。

我现在正在开发一个应用程序,在其中广泛使用新类型。 Haskell 中的 newtypes 纯粹是编译时概念。例如。使用下面的解包器,unFilename (Filename "x") 编译为与“x”相同的代码。运行时命中率绝对为零。有 data 类型。这使得它成为实现上述目标的一个非常好的方法。

-- | A file name (not a file path).
newtype Filename = Filename { unFilename :: String }
deriving (Show,Eq)

我不想意外地将其视为文件路径。它不是文件路径。它是数据库中某个位置的概念文件的名称。

对于算法来说,引用正确的事物非常重要,新类型可以帮助解决这一问题。这对于安全性也非常重要,例如,考虑将文件上传到 Web 应用程序。我有以下类型:

-- | 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.

从任意文件名生成唯一的文件名是危险的,应该首先对其进行清理。同样,唯一的文件名通过扩展名始终是安全的。如果我愿意,我现在可以将文件保存到磁盘并将该文件名放入我的数据库中。

但是必须多次包装/展开也可能很烦人。从长远来看,我认为这是值得的,特别是为了避免值(value)不匹配。 ViewPatterns 有一定帮助:

-- | Get the form fields for a form.
formFields :: ConferenceId -> Controller [Field]
formFields (unConferenceId -> cid) = getFields where
... code using cid ..

也许您会说在函数中展开它是一个问题 - 如果您错误地将 cid 传递给函数怎么办?不是问题,所有使用 session ID 的函数都将使用 ConferenceId 类型。出现的是一种在编译时强制执行的函数到函数级别的契约系统。很不错。所以是的,我尽可能经常使用它,尤其是在大型系统中。

关于就类型安全而言,Haskell 类型与 newtype,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/991467/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com