haskell - 如何在 haskell 中创建几种相关的数据类型?

标签 haskell types

我有一个 User 类型,表示数据库中保存的用户。但是,在显示用户时,我只想返回这些字段的子集,因此我创建了一个不带 hash 的不同类型。创建用户时,将提供密码而不是哈希,因此我为此创建了另一种类型。

这显然是最糟糕的,因为我的类型之间存在大量重复。有没有更好的方法来创建多个共享某些字段的相关类型,但添加一些字段并删除其他字段?

{-# LANGUAGE DeriveGeneric #}

data User = User {
  id :: String,
  email :: String,
  hash :: String,
  institutionId :: String
} deriving (Show, Generic)

data UserPrintable = UserPrintable {
  email :: String,
  id :: String,
  institutionId :: String
} deriving (Generic)

data UserCreatable = UserCreatable {
  email :: String,
  hash :: String,
  institutionId :: String
} deriving (Generic)

data UserFromRequest = UserFromRequest {
  email :: String,
  institutionId :: String,
  password :: String
} deriving (Generic)

-- UGHHHHHHHHHHH

最佳答案

在这种情况下,我认为您可以用函数替换各种 User 类型。因此,不要使用 UserFromRequest,而是:

userFromRequest :: Email -> InstitutionId -> String -> User

请注意如何为 EmailInstitutionId 创建单独的类型,这将帮助您避免一堆恼人的错误。这与将带有标记字段的记录作为参数具有相同的目的,同时还添加了一些额外的静态安全性。您可以将它们实现为新类型:

newtype Email = Email String deriving (Show, Eq)

同样,我们可以将 UserPrintable 替换为 showUser

然而,

UserCreatable 可能有点尴尬,具体取决于您需要如何使用它。如果您对它所做的只是将其作为参数并创建数据库行,那么您可以以相同的方式将其重构为函数。但如果您确实需要该类型来处理很多事情,那么这不是一个好的解决方案。

在第二种情况下,您有几个不错的选择。一种方法是将 id 设为 Maybe 并每次检查它。更好的方法是创建一个泛型类型 WithId a ,它只向任何内容添加一个 id 字段:

data WithId a = { id :: DatabaseId, content :: a }

然后有一个 no idUser 类型,并让您的数据库函数与 WithId User 一起使用。

关于haskell - 如何在 haskell 中创建几种相关的数据类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27553133/

相关文章:

haskell - 重叠实例的问题

haskell - 在 emacs 上使用 Hlint 和 intero

Haskell 约定 : Maybe or empty list?

generics - 具有静态解析类型参数的类型的自定义相等性

golang源码为什么要这样写

Haskell 缩进样式

haskell - 在 mac OS X 终端中使用 ctrl+D 时,stdin 的信号 EOF 不起作用

pointers - 如何获取指向被屏蔽为接口(interface)的变量的指针?

java - 泛型、对象、比较

haskell - 将类型参数限制为 Monoid