我有一个User
代表用户保存在数据库中的类型。但是,在显示用户时,我只想返回这些字段的子集,所以我做了一个不同的类型,而没有使用hash
。创建用户时,password
将提供a而不是a 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
请注意,您还可以如何为Email
和分别设置类型InstitutionId
,这将帮助您避免一堆烦人的错误。这与获取带有标记字段作为参数的记录的目的相同,同时还增加了一些额外的静态安全性。您可以将它们实现为新类型:
newtype Email = Email String deriving (Show, Eq)
同样的,我们可以更换UserPrintable
使用showUser
。
UserCreatable
但是可能有些尴尬,具体取决于您需要如何使用它。如果您所要做的只是将其作为参数并创建数据库行,则可以用相同的方式将其重构为函数。但是,如果您实际上需要一堆东西的类型,那么这不是一个好的解决方案。
在第二种情况下,您有几个不错的选择。一个就是每次做id
一个Maybe
并检查一下。更好的方法是创建一个通用类型WithId a
,该通用类型只id
向任何内容添加一个字段:
data WithId a = { id :: DatabaseId, content :: a }
然后User
使用no 的类型,id
并使数据库函数使用WithId User
。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句