谢谢newtype
和GeneralizedNewtypeDeriving
扩展,我们可以毫不费力地定义不同的轻量级类型:
newtype PersonId = PersonId Int deriving (Eq, Ord, Show, NFData, ...)
newtype GroupId = GroupId Int deriving (Eq, Ord, Show, NFData, ...)
这允许类型系统确保PersonId
不是偶然使用的GroupId
符合预期,但仍然继承选定的类型类实例Int
.
现在我们可以简单地定义PersonIdSet
and GroupIdSet
as
import Data.Set (Set)
import qualified Data.Set as Set
type PersonIdSet = Set PersonId
type GroupIdSet = Set GroupId
noGroups :: GroupIdSet
noGroups = Set.empty
-- should not type-check
foo = PersonId 123 `Set.member` noGroups
-- should type-check
bar = GroupId 123 `Set.member` noGroups
这是类型安全的,因为映射是由键类型参数化的,而且,Set.member
操作是多态的,所以我不需要定义每个 id 类型的变体,例如personIdSetMember
and groupIdSetMember
(以及我可能想要使用的所有其他设置操作)
...但是我怎样才能使用更有效的IntSet
s 代替PersonIdSet
and GroupIdSet
分别以与上面示例类似的方式?有没有一种简单的方法,无需将整个 Data.In Rest API 包装/复制为类型类?