如何“新类型” INTSET? [英] How to "newtype" IntSet?

查看:118
本文介绍了如何“新类型” INTSET?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

感谢 newtype GeneralizedNewtypeDeriving 扩展,您可以毫不费力地定义不同的轻量类型:

  newtype PersonId = PersonId Int派生(Eq,Ord,Show,NFData,...)
newtype GroupId = GroupId Int派生(Eq,Ord,Show,NFData,...)

允许类型系统确保在 GroupId 预期的情况下不会偶然使用 PersonId ,但仍会从<$ c继承选定的类型实例现在人们可以简单地定义 PersonIdSet 和<$ c


$ import $ Data Set
导入合格的数据Set as Set

类型PersonIdSet = Set PersonId
类型GroupIdSet = Set GroupId

noGroups :: GroupIdSet
noGroups = Set.empty

- 不应该类型检查
foo = PersonId 123`Set.member` noGroups

- should type-c heck
bar = GroupId 123`Set.member` noGroups

这是类型安全的,因为map是通过键类型参数化的,并且 Set.member 操作是多态的,所以我不需要定义每个id类型的变体,比如 personIdSetMember groupIdSetMember (以及其他所有可能要使用的设置操作)



...但我怎样才能使用效率更高的 IntSet s代替 PersonIdSet GroupIdSet 分别类似于上面的示例吗?有没有一种简单的方法,无需将整个Data.IntSet API作为类型类包装/复制?

解决方案

我认为如你所说,你必须包装 IntSet 。但是,不是单独定义每个ID类型,您可以引入一个幻像类型来创建 ID s和 IDSet

  { - #LANGUAGE GeneralizedNewtypeDeriving# - } 

导入

(Eq,Ord,Show,Num)Data.IntSet作为IntSet
导入Data.IntSet(IntSet)

newtype ID a = ID {unID :: Int}


newtype IDSet a = IDSet {unIDSet :: IntSet}
deriving(Eq,Ord,Show)
$ b $ null :: IDSet a - > Bool
null = IntSet.null。 unIDSet

成员:: ID a - > IDSet a - > Bool
成员i = IntSet.member(unID i)。 unIDSet

empty :: IDSet a
empty = IDSet $ IntSet.empty

singleton :: ID a - > ID设置
singleton = IDSet。 IntSet.singleton。 unID

insert :: ID a - > IDSet a - > IDSet a
插入i = IDSet。 IntSet.insert(unID i)。 unIDSet

delete :: ID a - > IDSet a - > IDSet a
删除i = IDSet。 IntSet.delete(unID i)。因此,假设你有一个 Person


>类型和组类型,您可以执行:

  type PersonID = ID Person 
类型PersonIDSet = IDSet Person

类型GroupID = ID Group
类型GroupIDSet = IDSet Group


Thanks to newtype and the GeneralizedNewtypeDeriving extension, one can define distinct lightweight types with little effort:

newtype PersonId = PersonId Int deriving (Eq, Ord, Show, NFData, ...)
newtype GroupId  = GroupId Int deriving (Eq, Ord, Show, NFData, ...)

which allows the type-system to make sure a PersonId is not used by accident where a GroupId was expected, but still inherit selected typeclass instances from Int.

Now one could simply define 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

which is type safe, since map is parametrized by the key-type, and also, the Set.member operation is polymorphic so I don't need to define per-id-type variants such as personIdSetMember and groupIdSetMember (and all other set-operations I might want to use)

...but how can I use the more efficient IntSets instead for PersonIdSet and GroupIdSet respectively in a similiar way to the example above? Is there a simple way w/o having to wrap/replicate the whole Data.IntSet API as a typeclass?

解决方案

I think you have to wrap IntSet as you said. However, rather than defining each ID type separately, you can introduce a phantom type to create a family of IDs and IDSets that are compatible with one another:

{-# LANGUAGE GeneralizedNewtypeDeriving #-}

import qualified Data.IntSet as IntSet
import Data.IntSet (IntSet)

newtype ID a = ID { unID :: Int }
              deriving ( Eq, Ord, Show, Num )

newtype IDSet a = IDSet { unIDSet :: IntSet }
              deriving ( Eq, Ord, Show )

null :: IDSet a -> Bool
null = IntSet.null . unIDSet

member :: ID a -> IDSet a -> Bool
member i = IntSet.member (unID i) . unIDSet

empty :: IDSet a
empty = IDSet $ IntSet.empty

singleton :: ID a -> IDSet a
singleton = IDSet . IntSet.singleton . unID

insert :: ID a -> IDSet a -> IDSet a
insert i = IDSet . IntSet.insert (unID i) . unIDSet

delete :: ID a -> IDSet a -> IDSet a
delete i = IDSet . IntSet.delete (unID i) . unIDSet

So, assuming you have a Person type, and a Group type, you can do:

type PersonID = ID Person
type PersonIDSet = IDSet Person

type GroupID = ID Group
type GroupIDSet = IDSet Group

这篇关于如何“新类型” INTSET?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆